Introduction

In this section, explain why you chose this topic, and the questions you are interested in studying. Include a brief description of how you found the data, and clear instructions on where the reader can find the data.

International travel has become so easy that anyone can just grab his/her bags and documents and starts a new journey. As one of the most tourists importing and exporting countries, the USA has always played a significant role in world’s tourism industry. Therefore, we want to study people who traveled to and from the USA by investigating the Travel and Tourism Statistical data provided by The National Travel & Tourism Office (NTTO). To be more precise, we want to answer following questions:

Data is collected from two resources,

http://tinet.ita.doc.gov/outreachpages/inbound.general_information.inbound_overview.asp

http://tinet.ita.doc.gov/view/m-2016-I-001/index.asp

http://travel.trade.gov/research/monthly/arrivals/index.asp

NTTO monthly spending NTTO yearly spending NTTO monthly inbound NTTO monthly outbound Word Bank GDP

From NTTO, … NTTO do not provide raw data

Although NTTO provides plenty of information we need, it is not easy to collect and combine them together. There is much unavoidable manual work to do in the collecting process because of the inconsistent formatting (data formats may vary from year to year), file types (some are pdfs) and location of these files. For example, in order to get monthly arrival information per region, we have to download each year’s excel files, and then clean, select and combine them into a final master table that is easier to manipulate with in R.

In the end, we collect several master tables from NTTO: yearly spending per region with three categories, total monthly spending with three categories, monthly inbound visitation per country and monthly outbound visitation per country. We may use other tables as complementary tables.

From World Bank,… On this website, we are trying to get GDP per country per year, as a measurement of economy.

GDP data from World Bank is easier to clean. Further, we will load these tables to R and use dplyr and tidyr to fit the data for our analysis.

Team

List team members and a description of how each contributed to the project. (If you’re working alone, briefly describe the stages of the project.)

Analysis of Data Quality

Provide a detailed, well-organized description of data quality, including textual description, graphs, and code.

library(tidyverse)
library(viridis)
library(ggvis)
library(extracat)
library(plotly)
library(zoo)
raw_ntto_spend_y <- tbl_df(read.csv("clean_data/clean_yearly_spending_region.csv", header = TRUE))
# raw_ntto_spend_m <- tbl_df(read.csv("clean_data/Monthly_Exports_Imports_Balance.csv", header = TRUE))
raw_ntto_inbound_m <- tbl_df(read.csv("clean_data/clean_monthly_visitation_inbound_country.csv", header = TRUE))
raw_ntto_outbound_m <- tbl_df(read.csv("clean_data/clean_monthly_us_to_international.csv", header = TRUE))
raw_wb_gdp <- tbl_df(read.csv("clean_data/API_NY.GDP.MKTP.CD_DS2_en_csv_v2.csv", header = TRUE, skip=4))

Data we have are: monthly spending from NTTO, yearly spending from NTTO, monthly inbound from NTTO, monthly outbound from NTTO and GDP from Word Bank. In order to analyze data quality of our data, we need first to take a look at them.

Output of str has been truncated to get a more compact look in report

str(raw_ntto_spend_y, list.len=5)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   48 obs. of  13 variables:
 $ region  : Factor w/ 8 levels "Africa","Asia-Pacific",..: 1 1 1 1 1 1 2 2 2 2 ...
 $ type    : Factor w/ 2 levels "Payments (imports)",..: 2 2 2 1 1 1 2 2 2 1 ...
 $ category: Factor w/ 3 levels "Education","Medical/Short-Term Workers",..: 1 2 3 1 2 3 1 2 3 1 ...
 $ X2006   : int  930 208 1390 137 29 1740 8566 836 23160 626 ...
 $ X2007   : int  961 183 1594 161 30 2435 9455 810 24756 667 ...
  [list output truncated]
# str(raw_ntto_spend_m, list.len=4)
str(raw_ntto_inbound_m, list.len=5)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   132 obs. of  32 variables:
 $ year                       : int  2015 2015 2015 2015 2015 2015 2015 2015 2015 2015 ...
 $ MONTH                      : Factor w/ 12 levels "APRIL","AUGUST",..: 5 4 8 1 9 7 6 2 12 11 ...
 $ TOTAL.ARRIVALS             : Factor w/ 132 levels "2,592,882","2,624,018",..: 91 70 109 119 124 110 130 131 120 121 ...
 $ CANADA                     : Factor w/ 132 levels "1,007,315","1,029,277",..: 63 39 109 96 89 50 112 120 71 44 ...
 $ MEXICO                     : Factor w/ 132 levels "1,004,126","1,007,303",..: 44 18 27 50 52 38 53 57 35 55 ...
  [list output truncated]
str(raw_ntto_outbound_m, list.len=4)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   102 obs. of  14 variables:
 $ Year   : int  2015 2015 2015 2015 2015 2015 2015 2015 2015 2015 ...
 $ Regions: Factor w/ 17 levels "Africa","Asia",..: 8 6 2 16 7 15 13 1 17 12 ...
 $ Jan    : Factor w/ 102 levels "1,707,635","1,716,026",..: 96 91 59 16 47 89 20 49 31 37 ...
 $ Feb    : Factor w/ 102 levels "1,514,915","1,580,058",..: 79 94 59 16 50 98 17 39 30 35 ...
  [list output truncated]
str(raw_wb_gdp, list.len=6)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   264 obs. of  62 variables:
 $ Country.Name  : Factor w/ 264 levels "Afghanistan",..: 11 1 6 2 5 8 250 9 10 4 ...
 $ Country.Code  : Factor w/ 264 levels "ABW","AFG","AGO",..: 1 2 3 4 5 6 7 8 9 10 ...
 $ Indicator.Name: Factor w/ 1 level "GDP (current US$)": 1 1 1 1 1 1 1 1 1 1 ...
 $ Indicator.Code: Factor w/ 1 level "NY.GDP.MKTP.CD": 1 1 1 1 1 1 1 1 1 1 ...
 $ X1960         : num  NA 5.38e+08 NA NA NA ...
 $ X1961         : num  NA 5.49e+08 NA NA NA ...
  [list output truncated]

The internal structure of these data indicates several data quality issues:

country_str <- 'Argentina|Australia|Brazil|Canada|Chile|China|Colombia|France|Germany|India|Italy|Japan|Mexico|Netherlands|Russia|Saudi Arabia|South Korea|Singapore|Spain|Sweden|Switzerland|Taiwan|United Kingdom|United States' 
tidy_ntto_spend_y <- raw_ntto_spend_y %>%
   gather(x_year, spend, -region, -type, -category) %>% 
   separate(x_year, c("X", "Year"), sep="X") %>% 
   select(-X) %>% 
   select(Region=region, Type=type, Category=category, Year=Year,Spend=spend) %>%  
   mutate(Region=gsub("^\\s+|\\s+$", "", Region)) %>% 
   mutate(Missing = ifelse(is.na(Spend), "yes", "no"), Region=tolower(Region), Year=factor(Year), Region=factor(Region))
tidy_ntto_inbound_m <- raw_ntto_inbound_m %>%
   mutate(as.character(TOTAL.ARRIVALS)) %>% 
   gather(key, val, -year, -MONTH) %>%
   mutate(Arrival=as.numeric(gsub('[^0-9]+', '', val)), Month=match(tolower(substr(MONTH, 1, 3)), tolower(month.abb)), key=tolower(gsub('\\.', ' ', key)), Year=year) %>%
   filter(!grepl("total", key)) %>%
   unite(YearMonth, year, Month, sep="-") %>%
   select(Year, YearMonth, MixRegion=key, Inbound=Arrival) %>% 
   mutate(MixRegion=recode(MixRegion, 
                           "latin america  excl mexico "="latin america excl mexico",
                           "prc  excl hk "="china",
                           "roc  taiwan "="taiwan")) %>% 
   mutate(Missing = ifelse(is.na(Inbound), "yes", "no"), Year=factor(Year), Date=as.yearmon(YearMonth), MixRegion=factor(MixRegion)) %>% 
   arrange(MixRegion, Date)
tidy_ntto_outbound_m <- raw_ntto_outbound_m %>% 
   gather(Month, Outbound, -Year, -Regions) %>% 
   mutate(Outbound=as.numeric(gsub('[^0-9]+', '', Outbound)), Month=match(Month, month.abb), MixRegion=tolower(gsub('\\([a-zA-Z0-9]+\\)', '', Regions)), year=Year) %>% 
   mutate(MixRegion=gsub("^\\s+|\\s+$", "", MixRegion)) %>% 
   filter(!grepl("air", MixRegion), !MixRegion=='total overseas', !MixRegion=='north america', !MixRegion=='grand total') %>% 
   unite(YearMonth, year, Month, sep="-") %>% 
   mutate(Region=recode(MixRegion, 
                        "caribbean"="latin america excl mexico",
                        "central america"="latin america excl mexico",
                        "south america"="latin america excl mexico")) %>% 
   mutate(Missing=ifelse(is.na(Outbound), "yes", "no"), Year=factor(Year), Date=as.yearmon(YearMonth), MixRegion=factor(MixRegion), Region=factor(Region)) %>% 
   select(Region, MixRegion, Year, Date, Missing, Outbound) %>% 
   arrange(Region, MixRegion, Date)
tidy_wb_gdp <- raw_wb_gdp %>% 
   select(-Indicator.Name, -Indicator.Code, -X) %>% 
   gather(x_year, GDP, -Country.Name, -Country.Code) %>% 
   filter(grepl(country_str, Country.Name)) %>% 
   separate(x_year, c("X", "Year"), sep="X") %>% 
   select(-X) %>% 
   select(CountryName=Country.Name, CountryCode=Country.Code, Year=Year, GDP=GDP) %>% 
   # filter(year>1999) %>% 
   mutate(Missing = ifelse(is.na(GDP), "yes", "no"))
ggplot(tidy_ntto_spend_y, aes(x=Year, y=Region, fill = Missing)) +
   geom_tile(color = "white") + 
   scale_fill_viridis(discrete = TRUE) +
   ggtitle("Missing Value of NTTO Yearly Spending Data") +
   theme_linedraw()

ggplot(tidy_ntto_inbound_m, aes(x=Date, y=MixRegion, fill = Missing)) +
   geom_tile(color = "white") + 
   scale_fill_viridis(discrete = TRUE) +
   ggtitle("Missing Value of NTTO Inbound Data") +
   theme_linedraw() +
   theme(axis.text.x=element_text(angle=90))

ggplot(tidy_ntto_outbound_m, aes(x=Date, y=MixRegion, fill = Missing)) +
   geom_tile(color = "white") + 
   scale_fill_viridis(discrete = TRUE) +
   ggtitle("Missing Value of NTTO Outbound Data") +
   theme_linedraw() +
   theme(axis.text.x=element_text(angle=90))

ggplot(tidy_wb_gdp, aes(x=Year, y=CountryName,  fill = Missing)) +
   geom_tile(color = "white") + 
   scale_fill_viridis(discrete = TRUE) +
   ggtitle("Missing Value of All Interested Countries (1960-2016)") +
   theme_linedraw() +
   theme(axis.text.x=element_text(angle=90)) 

Executive Summary

Provide a short nontechnical summary of the most revealing findings of your analysis with no more than 3 static graphs or one interactive graph (or link), written for a nontechnical audience. The length should be approximately 2 pages (if we were using pages…) Do not show code, and take extra care to clean up your graphs, ensuring that best practices for presentation are followed.

• Note: the tips below are not intended to be a complete list of everything we’ve covered this semester on designing a successful graph. It’s meant to help you avoid some common problems.

• Title, axis labels, tick mark labels, and legends should be comprehensible (easy to understand) and legible (easy to read / decipher).

• Tick marks should not be labeled in scientific notation or with long strings of zeros, such as 3000000000. Instead, convert to smaller numbers and change the units: 3000000000 becomes “3” and the axis label “billions of views”.

• Units should be intuitive (Extreme example: an axis labeled in month/day/year format is intuitive, one labeled in seconds since January 1, 1970 is not.)

• The font size should be large enough to read clearly. The default in ggplot2 is generally too small. You can easily change it by passing the base font size to the theme, such as + theme_grey(16). (The default base font size is 11.)

• The order of items on the axes and legends is logical. (Alphabetical is often not logical.)

• Colors should be color vision deficiency friendly.

• If a legend is taking up too much space on the right, move it to the bottom.

• If categorical variable levels are long, set up the graph so the categorical variable is on the y-axis and the names are horizontal. A better option, if possible, is to shorten the names of the levels.

• Not all EDA graphs lend themselves to presentation, either because the graph form is hard to understand without practice or it’s not well labeled. The labeling problem can be solved by adding text in an image editor. The downside is that it is not reproducible. If you want to go this route, Paintbrush is a free and simple bitmap image editor for the Mac: https://paintbrush.sourceforge.io/ There are many other options.

• Err on the side of simplicity. Don’t, for example, overuse color when it’s not necessary. Ask yourself: does color make this graph any clearer? If it doesn’t, leave it out.

• Test your graphs on nontechnical friends and family and ask for feedback.

Main Analysis

Provide a detailed, well-organized description of your findings, including textual description, graphs, and code. Your focus should be on both the results and the process. Include, as reasonable and relevant, approaches that didn’t work, challenges, the data cleaning process, etc.

• The guidelines for the Executive Summary above do NOT apply to exploratory data analysis. Your main concern is designing graphs that reveal patterns and trends.

• As noted in Hmk #4, do not use circles, that is: bubbles, pie charts, or polar coordinates.

• Use stacked bar charts sparingly. Try grouped bar charts and faceting as alternatives, and only choose stacked bar charts if they truly do a better job than the alternatives for observing patterns.

Data Cleaning

Since the data is very messy, we put many effort on cleaning and extract useful infomation for analysis.

  1. Convert to correct type
  2. Consolidate name, region, date

Join same region

region_str <- "africa|asia|canada|latin america (excl mexico)|europe|mexico|middle east|oceania"
inbound_region <- tidy_ntto_inbound_m %>% 
   filter(grepl(region_str, MixRegion)) %>% 
   select(Region=MixRegion, Year, Date, Inbound) %>% 
   group_by(Region, Year, Date) %>% 
   summarise(TotalInbound=sum(Inbound)) %>% 
   ungroup
outbound_region <- tidy_ntto_outbound_m %>% 
   select(Region, Year, Date, Outbound) %>% 
   group_by(Region, Year, Date) %>% 
   summarise(TotalOutbound=sum(Outbound)) %>% 
   ungroup
regional_travel <- inner_join(inbound_region, outbound_region, 
                              by=c("Region"="Region", "Year"="Year", "Date"="Date"))

Challenges

There are several challenges in our project:

  1. Due to the problems in the data set such as inconsistency, we have to spend much time in cleaning and re-organizing it, which makes the work tedious and laborious.
  2. We need country level data in some graphs; however, what we can acquire from the dataset is region level. In that case, we have to project the data onto the whole region, which makes the analysis not comprehensive and detailed.
  3. Shiny is a great tool for creating interactive data visualizations in R; however, we do not have much experience in it, and therefore have to spend time learning it, which is not easy in such a short time.

Analysis

Travel and Tourism Analysis

regional_travel %>% 
   select(Year, TotalInbound, TotalOutbound) %>% 
   group_by(Year) %>% 
   summarise(TotalInbound=sum(TotalInbound), TotalOutbound=sum(TotalOutbound)) %>% 
   plot_ly(x = ~Year, y = ~TotalInbound, type = 'bar', name = 'Inbound', marker = list(color = 'rgb(55, 83, 109)')) %>%
add_trace(y = ~TotalOutbound, name = 'Outbound', marker = list(color = 'rgb(26, 118, 255)')) %>%
layout(title = 'Yearly Inbound and Outbound',
      xaxis = list(
        title = "",
        tickfont = list(
          size = 14,
          color = 'rgb(107, 107, 107)')),
      yaxis = list(
        title = 'Number of People',
        titlefont = list(
          size = 16,
          color = 'rgb(107, 107, 107)'),
        tickfont = list(
          size = 14,
          color = 'rgb(107, 107, 107)')),
      legend = list(orientation = 'h', x = 0, y = 1, 
                    bgcolor = 'rgba(255, 255, 255, 0)', bordercolor = 'rgba(255, 255, 255, 0)'),
      barmode = 'group', bargap = 0.15)

The United States is one of the largest destinations for visitors and has a large amount outbound journeys as well. The numbers of inbound and outbound have increased a lot from 2009 to 2010. Between 2010 to 2013, the number of international visitors raised a little bit each year however the amound of outbound is kind of stable. Since 2013, both of them grown a lot and finally achieved 77.5 million international visitations and 85.6 million outbound travellers in 2015.

Naturally we start wondering what are the most popular destination for americans and where are these international vistors come from? To answer these questions, we break down the graph into smaller regions.

p1 <- inbound_region %>% 
   spread(Region, TotalInbound) %>% 
   filter(Date>'2008-11') %>% 
   plot_ly(x = ~as.POSIXct(Date)) %>%
   add_trace(y=~africa, name='africa', mode='lines', line = list(color="gray", width = 1)) %>%
   add_trace(y=~asia, name='asia', mode='lines', line = list(color="red", width = 1)) %>%
   add_trace(y=~canada, name='canada', mode='lines', line = list(color="orange", width = 1)) %>%
   add_trace(y=~europe, name='europe', mode='lines', line = list(color="pink", width = 1)) %>%
   add_trace(y=~`latin america excl mexico`, name='latin america excl mexico', mode='lines', line = list(color="green", width = 1)) %>%
   add_trace(y=~mexico, name='mexico', mode='lines', line = list(color="purple", width = 1)) %>%
   add_trace(y=~`middle east`, name='middle east', mode='lines', line = list(color="black", width = 1)) %>%
   add_trace(y=~oceania, name='oceania', mode='lines', line = list(color="blue", width = 1)) 
p2 <- outbound_region %>% spread(Region, TotalOutbound) %>% 
   plot_ly(x = ~as.POSIXct(Date)) %>%
   add_trace(y=~africa, name='africa', mode='lines', line = list(color="gray", width = 1), showlegend=F) %>%
   add_trace(y=~asia, name='asia', mode='lines', line = list(color="red", width = 1), showlegend=F) %>%
   add_trace(y=~canada, name='canada', mode='lines', line = list(color="orange", width = 1), showlegend=F) %>%
   add_trace(y=~europe, name='europe', mode='lines', line = list(color="pink", width = 1), showlegend=F) %>%
   add_trace(y=~`latin america excl mexico`, name='latin america excl mexico', mode='lines', line = list(color="green", width = 1), showlegend=F) %>%
   add_trace(y=~mexico, name='mexico', mode='lines', line = list(color="purple", width = 1), showlegend=F) %>%
   add_trace(y=~`middle east`, name='middle east', mode='lines', line = list(color="black", width = 1), showlegend=F) %>%
   add_trace(y=~oceania, name='oceania', mode='lines', line = list(color="blue", width = 1), showlegend=F)
subplot(p1, p2, nrows=2, shareX=T) %>%
  layout(title = "Inbound v.s. Outbound",
         yaxis = list(title = "Inbound"),
         yaxis2 = list(title = "Outbound"),
         legend = list(orientation = 'h')
         )

After separating each region out, we observed several things:

  • Most of the international travellers are come from Canada, Mexico, Europe, and Asia.
  • Mexico, Canada, Europe, and Latin America except Mexico are the top destinations for americans.
  • Seasonality exists in each line. Usually peak is reached in summer. For example, every year of July, the number of canada vistors reaches its highest peak of the year.
  • A boom in amount of visitors from Latin America except Mexico in the begining of 2014 and a boom in amount of people travel to Mexico in the start of 2010.

We further draws inbound and outbound per region to better explore the hidden pattern individually.

p1 <- regional_travel %>% 
   filter(Region=='africa') %>% 
   plot_ly(x = ~as.POSIXct(Date), height = 1000) %>%
   add_trace(y=~TotalInbound, type="scatter", name='Inbound', mode='lines', line = list(color="gray", width = 1)) %>%
   add_trace(y=~TotalOutbound, type="scatter", name='Outbound', mode='lines', line = list(color="blue", width = 1)) %>% 
   layout(autosize=F)
p2 <- regional_travel %>% 
   filter(Region=='asia') %>% 
   plot_ly(x = ~as.POSIXct(Date)) %>%
   add_trace(y=~TotalInbound, type="scatter", name='Inbound', mode='lines', line = list(color="gray", width = 1), showlegend=F) %>%
   add_trace(y=~TotalOutbound, type="scatter", name='Outbound', mode='lines', line = list(color="blue", width = 1), showlegend=F)
p3 <- regional_travel %>% 
   filter(Region=='canada') %>% 
   plot_ly(x = ~as.POSIXct(Date)) %>%
   add_trace(y=~TotalInbound, type="scatter", name='Inbound', mode='lines', line = list(color="gray", width = 1), showlegend=F) %>%
   add_trace(y=~TotalOutbound, type="scatter", name='Outbound', mode='lines', line = list(color="blue", width = 1), showlegend=F)
p4 <- regional_travel %>% 
   filter(Region=='europe') %>% 
   plot_ly(x = ~as.POSIXct(Date)) %>%
   add_trace(y=~TotalInbound, type="scatter", name='Inbound', mode='lines', line = list(color="gray", width = 1), showlegend=F) %>%
   add_trace(y=~TotalOutbound, type="scatter", name='Outbound', mode='lines', line = list(color="blue", width = 1), showlegend=F)
p5 <- regional_travel %>% 
   filter(Region=='latin america excl mexico') %>% 
   plot_ly(x = ~as.POSIXct(Date)) %>%
   add_trace(y=~TotalInbound, type="scatter", name='Inbound', mode='lines', line = list(color="gray", width = 1), showlegend=F) %>%
   add_trace(y=~TotalOutbound, type="scatter", name='Outbound', mode='lines', line = list(color="blue", width = 1), showlegend=F)
p6 <- regional_travel %>% 
   filter(Region=='mexico') %>% 
   plot_ly(x = ~as.POSIXct(Date)) %>%
   add_trace(y=~TotalInbound, type="scatter", name='Inbound', mode='lines', line = list(color="gray", width = 1), showlegend=F) %>%
   add_trace(y=~TotalOutbound, type="scatter", name='Outbound', mode='lines', line = list(color="blue", width = 1), showlegend=F)
p7 <- regional_travel %>% 
   filter(Region=='middle east') %>% 
   plot_ly(x = ~as.POSIXct(Date)) %>%
   add_trace(y=~TotalInbound, type="scatter", name='Inbound', mode='lines', line = list(color="gray", width = 1), showlegend=F) %>%
   add_trace(y=~TotalOutbound, type="scatter", name='Outbound', mode='lines', line = list(color="blue", width = 1), showlegend=F)
p8 <- regional_travel %>% 
   filter(Region=='oceania') %>% 
   plot_ly(x = ~as.POSIXct(Date)) %>%
   add_trace(y=~TotalInbound, type="scatter", name='Inbound', mode='lines', line = list(color="gray", width = 1), showlegend=F) %>%
   add_trace(y=~TotalOutbound, type="scatter", name='Outbound', mode='lines', line = list(color="blue", width = 1), showlegend=F)
subplot(p1, p2, p3, p4, p5, p6, p7, p8, nrows=8) %>%
  layout(title = "Regional Inbound and Outbound",
         yaxis = list(title = "Africa"),
         yaxis2 = list(title = "Asia"), 
         yaxis3 = list(title = "Canada"),
         yaxis4 = list(title = "Europe"),
         yaxis5 = list(title = "Latin America"),
         yaxis6 = list(title = "Mexico"),
         yaxis7 = list(title = "Middle East"),
         yaxis8 = list(title = "Oceania"),
         legend = list(orientation = 'h', x = 0, y = 1.005)
         )
  • Africa: There are more and more people from Africa travel to U.S. since 2013, but the number of american who go to Africa is very stable for past 7 years.

  • Asia: More and more Asias come to U.S, however, less Americans go to Asia after May 2010. Another thing to notice is the number of visitors from Asia grows faster in July compare to other month. This is probabaly due to the increase of foreign students.

  • Canada:

  • Europe:

  • Latin America except Mexico:

  • Mexico: A boom of number of outbound happens in the end of 2009. We did a lot research online and found news about with topics about More Mexicans Leaving Than Coming to the U.S. So we think the

  • Middle East: Both the number of inbound and outbound increase by year.

  • Oceania: Like Asia, less of U.S. citizens visit Oceania region since mid 2010.

Then we move to the Outbound of all regions, from graph belowe we observe several things: 1. Mexico is the number one Outbound country. 2. A huge pump happend on 2009 for Mexico. 3. Outbound number of mexico is increasing, however for other regions it seems stable. 4. Like Inbound, Outbound shows a seasonal pattern as well.

Since Canada and Mexico dominate the number of people and the interest of different behaviour per region, we start looking at inbound and outbound per region.

Spend Analysis

yearly_spend <- tidy_ntto_spend_y %>% 
   filter(Region!='european union', Region!='south-central america', Region!='overseas') %>% 
   mutate(Region=recode(Region, "asia-pacific"="asia"), Spend=Spend*1000000) %>% 
   select(-Missing) %>% 
   arrange(Region, Year, Type, Category) 
yearly_spend %>%
   group_by(Type, Year) %>%
   summarise(TotalSpend=sum(Spend)) %>% 
   spread(Type, TotalSpend) %>%
   ungroup %>% 
   plot_ly(x = ~Year) %>%
   add_trace(y=~`Payments (imports)`, type="scatter", name='Payments (imports)', mode = 'lines+markers', line = list(color="blue", width = 1)) %>%
   add_trace(y=~`Receipts (exports)`, type="scatter", name='Receipts (exports)', mode = 'lines+markers', line = list(width = 1)) %>% 
   layout(title = "Yearly Spending", 
          xaxis = list(title = "Year"), yaxis = list(title = "Spend"), 
          legend = list(orientation = 'h', x = 0.5, y = 1.005))
yearly_spend %>%
   group_by(Type, Year) %>%
   summarise(TotalSpend=sum(Spend)) %>% 
   spread(Type, TotalSpend) %>%
   plot_ly(x = ~Year, y = ~`Payments (imports)`, type = 'bar', name = 'Payments', marker = list(color = 'rgb(55, 83, 109)')) %>%
   add_trace(y = ~`Receipts (exports)`, name = 'Receipts', marker = list(color = 'rgb(26, 118, 255)')) %>%
   layout(title = 'Yearly Spending',
         xaxis = list(
           title = "",
           tickfont = list(
             size = 14,
             color = 'rgb(107, 107, 107)')),
         yaxis = list(
           title = 'Spend (Billion $)',
           titlefont = list(
             size = 16,
             color = 'rgb(107, 107, 107)'),
           tickfont = list(
             size = 14,
             color = 'rgb(107, 107, 107)')),
         legend = list(orientation = 'h', x = 0, y = 1, 
                       bgcolor = 'rgba(255, 255, 255, 0)', bordercolor = 'rgba(255, 255, 255, 0)'),
         barmode = 'group', bargap = 0.15, bargroupgap = 0.1)
yearly_spend %>% 
   filter(Type=="Payments (imports)") %>% 
   select(-Type) %>% 
   group_by(Region, Year) %>% 
   summarise(TotalSpend=sum(Spend)) %>% 
   spread(Region, TotalSpend) %>% 
   plot_ly(x = ~Year) %>%
   add_trace(y=~africa, type="scatter", name='africa', mode = 'lines+markers', line = list(width = 2)) %>%
   add_trace(y=~asia, type="scatter", name='asia', mode = 'lines+markers', line = list(width = 2)) %>%
   add_trace(y=~europe, type="scatter", name='europe', mode = 'lines+markers', line = list(width = 2)) %>%
   add_trace(y=~`latin america`, type="scatter", name='latin america', mode = 'lines+markers', line = list(width = 2)) %>%
   add_trace(y=~`middle east`, type="scatter", name='middle east', mode = 'lines+markers', line = list(width = 2)) %>% 
   layout(title = "Payments (imports)", 
          xaxis = list(title = "Year"), 
          yaxis = list(title = "Spend"),
          legend = list(orientation = 'h'))
yearly_spend %>% 
   filter(Type=="Receipts (exports)") %>% 
   select(-Type) %>% 
   group_by(Region, Year) %>% 
   summarise(TotalSpend=sum(Spend)) %>% 
   spread(Region, TotalSpend) %>% 
   plot_ly(x = ~Year) %>%
   add_trace(y=~africa, type="scatter", name='africa', mode = 'lines+markers', line = list(width = 1)) %>%
   add_trace(y=~asia, type="scatter", name='asia', mode = 'lines+markers', line = list(width = 1)) %>%
   add_trace(y=~europe, type="scatter", name='europe', mode = 'lines+markers', line = list(width = 1)) %>%
   add_trace(y=~`latin america`, type="scatter", name='latin america', mode = 'lines+markers', line = list(width = 1)) %>%
   add_trace(y=~`middle east`, type="scatter", name='middle east', mode = 'lines+markers', line = list(width = 1)) %>% 
   layout(title = "Receipts (exports)", 
          xaxis = list(title = "Year"), 
          yaxis = list(title = "Spend"), 
          legend = list(orientation = 'h'))
yearly_spend %>%
   group_by(Type, Year) %>%
   summarise(TotalSpend=sum(Spend)) %>% 
   spread(Type, TotalSpend) %>%
   plot_ly(x = ~Year) %>%
   add_trace(y=~`Payments (imports)`, type="scatter", name='Payments (imports)', mode = 'lines+markers', line = list(color="blue", width = 1)) %>%
   add_trace(y=~`Receipts (exports)`, type="scatter", name='Receipts (exports)', mode = 'lines+markers', line = list(width = 1)) %>% 
   layout(title = "Africa", 
          xaxis = list(title = "Year"), yaxis = list(title = "Spend"), 
          legend = list(orientation = 'h', x = 0.5, y = 1.005))
tidy_wb_gdp %>% 
   filter(CountryCode=="USA", Year>2000, Year<2016) %>% 
   select(Year, GDP) %>% 
   mutate(Year=factor(Year)) %>% 
   plot_ly(x = ~Year) %>%
   add_trace(y=~GDP, type="scatter", name='US', mode = 'lines+markers', line = list(width = 1))
yearly_spend %>% 
   filter(Type=="Receipts (exports)") %>% 
   select(-Type, -Region) %>% 
   group_by(Category, Year) %>% 
   summarise(TotalSpend=sum(Spend)) %>% 
   spread(Category, TotalSpend) %>% 
   plot_ly(x = ~Year, y = ~Education, type = 'bar', name = 'Education') %>%
   add_trace(y = ~`Medical/Short-Term Workers`, name = 'Medical/Short-Term Workers') %>% 
   add_trace(y = ~`Other Business/Other Personal Travel`, name = 'Other Business/Other Personal Travel') %>% 
   layout(yaxis = list(title = 'Spend'), barmode = 'group')
yearly_spend %>% 
   filter(Type=="Receipts (exports)") %>% 
   select(-Type, -Region) %>% 
   group_by(Category, Year) %>% 
   summarise(TotalSpend=sum(Spend)) %>% 
   spread(Category, TotalSpend) %>% 
   plot_ly(x = ~Year, y = ~Education, type = 'bar', name = 'Education') %>%
   add_trace(y = ~`Medical/Short-Term Workers`, name = 'Medical/Short-Term Workers') %>% 
   add_trace(y = ~`Other Business/Other Personal Travel`, name = 'Other Business/Other Personal Travel') %>% 
   layout(yaxis = list(title = 'Spend'), barmode = 'group')

Finally, we select several region and combine inbound, outbound with GDP

Conclusion

Discuss limitations and future directions, lessons learned.

A note on style: You are encouraged to be as intellectually honest as possible. That means pointing out flaws in your work, detailing obstacles, disagreements, decision points, etc. – the kinds of “behind-the-scene” things that are important but often left out of reports. You may use the first person (“I”/“We”) or specific team members’ names, as relevant.

The goal of this project is to answer the four questions raised above. We have accomplished the task despite of some flaws and limitations. For instance, the latest data we could find is for the year 2015, which is more than one year ago. In that case, we could not say the analysis is very persuasive since the data source is not up to date. We are unable to get data that are more detailed so that we cannot dig deeper to find root causes of some observations. At the very beginning, we thought the data was exhaustive and comprehensive and we made plenty of hypotheses and expectations based on the first impression; however, we find that most of our ideas are not realistic as we investigate the data more. Unfortunately, we have to discard some interesting ideas due the inconstancy in the dataset. For the future work, we could introduce more supportive data such as the inbound and outbound traveler data of other countries, and then compare it with the USA. We believe that it would reveal results that are more interesting.

LS0tCnRpdGxlOiAiRURBIEZpbmFsIFJlcG9ydCIKYXV0aG9yOiAiTHVjeSBMdSAoeGwyNjAyKSwgSGFubGluIFd1IChodzI1NzYpIgpvdXRwdXQ6IAogICBodG1sX25vdGVib29rOgogICAgICB0b2M6IHRydWUKICAgICAgdGhlbWU6IHVuaXRlZAogICAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgojIyBJbnRyb2R1Y3Rpb24KPiBJbiB0aGlzIHNlY3Rpb24sIGV4cGxhaW4gd2h5IHlvdSBjaG9zZSB0aGlzIHRvcGljLCBhbmQgdGhlIHF1ZXN0aW9ucyB5b3UgYXJlIGludGVyZXN0ZWQgaW4gc3R1ZHlpbmcuIEluY2x1ZGUgYSBicmllZiBkZXNjcmlwdGlvbiBvZiBob3cgeW91IGZvdW5kIHRoZSBkYXRhLCBhbmQgY2xlYXIgaW5zdHJ1Y3Rpb25zIG9uIHdoZXJlIHRoZSByZWFkZXIgY2FuIGZpbmQgdGhlIGRhdGEuCgpJbnRlcm5hdGlvbmFsIHRyYXZlbCBoYXMgYmVjb21lIHNvIGVhc3kgdGhhdCBhbnlvbmUgY2FuIGp1c3QgZ3JhYiBoaXMvaGVyIGJhZ3MgYW5kIGRvY3VtZW50cyBhbmQgc3RhcnRzIGEgbmV3IGpvdXJuZXkuIEFzIG9uZSBvZiB0aGUgbW9zdCB0b3VyaXN0cyBpbXBvcnRpbmcgYW5kIGV4cG9ydGluZyBjb3VudHJpZXMsIHRoZSBVU0EgaGFzIGFsd2F5cyBwbGF5ZWQgYSBzaWduaWZpY2FudCByb2xlIGluIHdvcmxk4oCZcyB0b3VyaXNtIGluZHVzdHJ5LiBUaGVyZWZvcmUsIHdlIHdhbnQgdG8gc3R1ZHkgcGVvcGxlIHdobyB0cmF2ZWxlZCB0byBhbmQgZnJvbSB0aGUgVVNBIGJ5IGludmVzdGlnYXRpbmcgdGhlIFRyYXZlbCBhbmQgVG91cmlzbSBTdGF0aXN0aWNhbCBkYXRhIHByb3ZpZGVkIGJ5IFRoZSBOYXRpb25hbCBUcmF2ZWwgJiBUb3VyaXNtIE9mZmljZSAoTlRUTykuIFRvIGJlIG1vcmUgcHJlY2lzZSwgd2Ugd2FudCB0byBhbnN3ZXIgZm9sbG93aW5nIHF1ZXN0aW9uczoKCi0JV2hhdCBhcmUgdGhlIG1vc3QgcG9wdWxhciBpbnRlcm5hdGlvbmFsIHRyYXZlbCBkZXN0aW5hdGlvbnMgZm9yIEFtZXJpY2Fucz8KCi0JV2hhdCBhcmUgdGhlIG1haW4gcmVnaW9ucyBvZiBwZW9wbGUgd2hvIHRyYXZlbCB0byB0aGUgVVNBPwoKLQlXaGF0IGFyZSB0aGUgcHVycG9zZXMgYW5kIHNwZW5kaW5nIG9mIHRyYXZlbHMgdG8gYW5kIGZyb20gdGhlIFVTQT8KCi0JRG9lcyB0aGUgZWNvbm9teSBtYXR0ZXIgZm9yIHRoZSBhbnN3ZXJzIHRvIGFib3ZlIHF1ZXN0aW9ucz8KCgpEYXRhIGlzIGNvbGxlY3RlZCBmcm9tIHR3byByZXNvdXJjZXMsCgotCWBOYXRpb25hbCBUcmF2ZWwgJiBUb3VyaXNtIE9mZmljZSAoTlRUTylgOgogICAgKyBbYEluYm91bmQgSW5mb3JtYXRpb25gXShodHRwOi8vdHJhdmVsLnRyYWRlLmdvdi9vdXRyZWFjaHBhZ2VzL2luYm91bmQuZ2VuZXJhbF9pbmZvcm1hdGlvbi5pbmJvdW5kX292ZXJ2aWV3Lmh0bWwpCiAgICArIFtgT3V0Ym91bmQgSW5mb3JtYXRpb25gXShodHRwOi8vdHJhdmVsLnRyYWRlLmdvdi9vdXRyZWFjaHBhZ2VzL291dGJvdW5kLmdlbmVyYWxfaW5mb3JtYXRpb24ub3V0Ym91bmRfb3ZlcnZpZXcuaHRtbCkgCi0gW2BXb3JsZCBCYW5rYF0oaHR0cDovL2RhdGEud29ybGRiYW5rLm9yZy9pbmRpY2F0b3IvTlkuR0RQLk1LVFAuQ0QpOiAKCgpodHRwOi8vdGluZXQuaXRhLmRvYy5nb3Yvb3V0cmVhY2hwYWdlcy9pbmJvdW5kLmdlbmVyYWxfaW5mb3JtYXRpb24uaW5ib3VuZF9vdmVydmlldy5hc3AKCmh0dHA6Ly90aW5ldC5pdGEuZG9jLmdvdi92aWV3L20tMjAxNi1JLTAwMS9pbmRleC5hc3AKCmh0dHA6Ly90cmF2ZWwudHJhZGUuZ292L3Jlc2VhcmNoL21vbnRobHkvYXJyaXZhbHMvaW5kZXguYXNwCgpOVFRPIG1vbnRobHkgc3BlbmRpbmcKTlRUTyB5ZWFybHkgc3BlbmRpbmcgCk5UVE8gbW9udGhseSBpbmJvdW5kIApOVFRPIG1vbnRobHkgb3V0Ym91bmQKV29yZCBCYW5rIEdEUCAKCgpGcm9tIE5UVE8sIC4uLgpOVFRPIGRvIG5vdCBwcm92aWRlIHJhdyBkYXRhCgpBbHRob3VnaCBOVFRPIHByb3ZpZGVzIHBsZW50eSBvZiBpbmZvcm1hdGlvbiB3ZSBuZWVkLCBpdCBpcyBub3QgZWFzeSB0byBjb2xsZWN0IGFuZCBjb21iaW5lIHRoZW0gdG9nZXRoZXIuIFRoZXJlIGlzIG11Y2ggdW5hdm9pZGFibGUgbWFudWFsIHdvcmsgdG8gZG8gaW4gdGhlIGNvbGxlY3RpbmcgcHJvY2VzcyBiZWNhdXNlIG9mIHRoZSBpbmNvbnNpc3RlbnQgZm9ybWF0dGluZyAoZGF0YSBmb3JtYXRzIG1heSB2YXJ5IGZyb20geWVhciB0byB5ZWFyKSwgZmlsZSB0eXBlcyAoc29tZSBhcmUgcGRmcykgYW5kIGxvY2F0aW9uIG9mIHRoZXNlIGZpbGVzLiBGb3IgZXhhbXBsZSwgaW4gb3JkZXIgdG8gZ2V0IG1vbnRobHkgYXJyaXZhbCBpbmZvcm1hdGlvbiBwZXIgcmVnaW9uLCB3ZSBoYXZlIHRvIGRvd25sb2FkIGVhY2ggeWVhcuKAmXMgZXhjZWwgZmlsZXMsIGFuZCB0aGVuIGNsZWFuLCBzZWxlY3QgYW5kIGNvbWJpbmUgdGhlbSBpbnRvIGEgZmluYWwgbWFzdGVyIHRhYmxlIHRoYXQgaXMgZWFzaWVyIHRvIG1hbmlwdWxhdGUgd2l0aCBpbiBSLiAKCkluIHRoZSBlbmQsIHdlIGNvbGxlY3Qgc2V2ZXJhbCBtYXN0ZXIgdGFibGVzIGZyb20gTlRUTzogeWVhcmx5IHNwZW5kaW5nIHBlciByZWdpb24gd2l0aCB0aHJlZSBjYXRlZ29yaWVzLCB0b3RhbCBtb250aGx5IHNwZW5kaW5nIHdpdGggdGhyZWUgY2F0ZWdvcmllcywgbW9udGhseSBpbmJvdW5kIHZpc2l0YXRpb24gcGVyIGNvdW50cnkgYW5kIG1vbnRobHkgb3V0Ym91bmQgdmlzaXRhdGlvbiBwZXIgY291bnRyeS4gV2UgbWF5IHVzZSBvdGhlciB0YWJsZXMgYXMgY29tcGxlbWVudGFyeSB0YWJsZXMuCgpGcm9tIFdvcmxkIEJhbmssLi4uIApPbiB0aGlzIHdlYnNpdGUsIHdlIGFyZSB0cnlpbmcgdG8gZ2V0IEdEUCBwZXIgY291bnRyeSBwZXIgeWVhciwgYXMgYSBtZWFzdXJlbWVudCBvZiBlY29ub215LgoKR0RQIGRhdGEgZnJvbSBXb3JsZCBCYW5rIGlzIGVhc2llciB0byBjbGVhbi4gRnVydGhlciwgd2Ugd2lsbCBsb2FkIHRoZXNlIHRhYmxlcyB0byBSIGFuZCB1c2UgZHBseXIgYW5kIHRpZHlyIHRvIGZpdCB0aGUgZGF0YSBmb3Igb3VyIGFuYWx5c2lzLiAKCgojIyBUZWFtCj4gTGlzdCB0ZWFtIG1lbWJlcnMgYW5kIGEgZGVzY3JpcHRpb24gb2YgaG93IGVhY2ggY29udHJpYnV0ZWQgdG8gdGhlIHByb2plY3QuIChJZiB5b3UncmUgd29ya2luZyBhbG9uZSwgYnJpZWZseSBkZXNjcmliZSB0aGUgc3RhZ2VzIG9mIHRoZSBwcm9qZWN0LikKCi0gTHVjeSBMdTogIGZpbmRpbmcgYW5kIG9yZ2FuaXppbmcgdGhlIGRhdGEsIGNvbXBpbGluZyB2aXN1YWxpemF0aW9uIGFuZCBzdG9yaWVzLCBjcmVhdGluZyB0aGUgaW50ZXJhY3RpdmUgYXBwLCBmb2N1c2luZyBvbiB0aGUgaW1wb3J0IHBhcnQuCgotIEhhbmxpbiBXdTogY2xlYW5pbmcgdGhlIGRhdGEsIHRlc3RpbmcgdmFyaW91cyB2aXN1YWxpemF0aW9ucywgY3JlYXRpbmcgdGhlIGludGVyYWN0aXZlIGFwcCwgZm9jdXNpbmcgb24gdGhlIGV4cG9ydCBwYXJ0LgoKCiMjIEFuYWx5c2lzIG9mIERhdGEgUXVhbGl0eQo+IFByb3ZpZGUgYSBkZXRhaWxlZCwgd2VsbC1vcmdhbml6ZWQgZGVzY3JpcHRpb24gb2YgZGF0YSBxdWFsaXR5LCBpbmNsdWRpbmcgdGV4dHVhbCBkZXNjcmlwdGlvbiwgZ3JhcGhzLCBhbmQgY29kZS4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KGdndmlzKQpsaWJyYXJ5KGV4dHJhY2F0KQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeSh6b28pCmBgYAoKYGBge3IsIG1lc3NhZ2U9RkFMU0V9CnJhd19udHRvX3NwZW5kX3kgPC0gdGJsX2RmKHJlYWQuY3N2KCJjbGVhbl9kYXRhL2NsZWFuX3llYXJseV9zcGVuZGluZ19yZWdpb24uY3N2IiwgaGVhZGVyID0gVFJVRSkpCiMgcmF3X250dG9fc3BlbmRfbSA8LSB0YmxfZGYocmVhZC5jc3YoImNsZWFuX2RhdGEvTW9udGhseV9FeHBvcnRzX0ltcG9ydHNfQmFsYW5jZS5jc3YiLCBoZWFkZXIgPSBUUlVFKSkKcmF3X250dG9faW5ib3VuZF9tIDwtIHRibF9kZihyZWFkLmNzdigiY2xlYW5fZGF0YS9jbGVhbl9tb250aGx5X3Zpc2l0YXRpb25faW5ib3VuZF9jb3VudHJ5LmNzdiIsIGhlYWRlciA9IFRSVUUpKQpyYXdfbnR0b19vdXRib3VuZF9tIDwtIHRibF9kZihyZWFkLmNzdigiY2xlYW5fZGF0YS9jbGVhbl9tb250aGx5X3VzX3RvX2ludGVybmF0aW9uYWwuY3N2IiwgaGVhZGVyID0gVFJVRSkpCnJhd193Yl9nZHAgPC0gdGJsX2RmKHJlYWQuY3N2KCJjbGVhbl9kYXRhL0FQSV9OWS5HRFAuTUtUUC5DRF9EUzJfZW5fY3N2X3YyLmNzdiIsIGhlYWRlciA9IFRSVUUsIHNraXA9NCkpCmBgYAoKRGF0YSB3ZSBoYXZlIGFyZTogbW9udGhseSBzcGVuZGluZyBmcm9tIE5UVE8sIHllYXJseSBzcGVuZGluZyBmcm9tIE5UVE8sIG1vbnRobHkgaW5ib3VuZCBmcm9tIE5UVE8sIG1vbnRobHkgb3V0Ym91bmQgZnJvbSBOVFRPIGFuZCBHRFAgZnJvbSBXb3JkIEJhbmsuIEluIG9yZGVyIHRvIGFuYWx5emUgZGF0YSBxdWFsaXR5IG9mIG91ciBkYXRhLCB3ZSBuZWVkIGZpcnN0IHRvIHRha2UgYSBsb29rIGF0IHRoZW0uIAoKKk91dHB1dCBvZiBgc3RyYCBoYXMgYmVlbiB0cnVuY2F0ZWQgdG8gZ2V0IGEgbW9yZSBjb21wYWN0IGxvb2sgaW4gcmVwb3J0KiAKCi0gWWVhcmx5IFNwZW5kaW5nIGZyb20gTlRUTwpgYGB7cn0Kc3RyKHJhd19udHRvX3NwZW5kX3ksIGxpc3QubGVuPTUpCmBgYAoKLSBNb250aGx5IFNwZW5kaW5nIGZyb20gTlRUTwpgYGB7cn0KIyBzdHIocmF3X250dG9fc3BlbmRfbSwgbGlzdC5sZW49NCkKYGBgCgotIE1vbnRobHkgSW5ib3VuZCBmcm9tIE5UVE8gCmBgYHtyfQpzdHIocmF3X250dG9faW5ib3VuZF9tLCBsaXN0Lmxlbj01KQpgYGAKCi0gTW9udGhseSBPdXRib3VuZCBmcm9tIE5UVE8KYGBge3J9CnN0cihyYXdfbnR0b19vdXRib3VuZF9tLCBsaXN0Lmxlbj00KQpgYGAKCi0gR0RQIGZyb20gV29yZCBCYW5rCmBgYHtyfQpzdHIocmF3X3diX2dkcCwgbGlzdC5sZW49NikKYGBgCgpUaGUgaW50ZXJuYWwgc3RydWN0dXJlIG9mIHRoZXNlIGRhdGEgaW5kaWNhdGVzIHNldmVyYWwgZGF0YSBxdWFsaXR5IGlzc3VlczoKCiogTm90IHRpZHk6CiAgICAgICsgSXQgaXMgYmV0dGVyIGluIG91ciBjYXNlIHRvIGhhdmUgYSBjb2x1bW5zIG5hbWVkIGBZZWFyYCBpbnN0ZWFkIG9mIGVhY2ggeWVhciBoYXMgaXRzIG93biBjb2x1bW4uIAoqIE1lc3N5IGNvbHVtbiBuYW1lczoKICAgICAgKyBTb21lIGNvbHVtbnMgbGlrZSBgWDE5NjBgIGlzIHdlaXJkIGFuZCB3ZSBzaG91bGQgcmVtb3ZlIHRoZSBleHRyYSAiWCIuCiogV3JvbmcgdHlwZXMgb2YgdmFsdWVzOgogICAgICArIFNvbWUgbnVtZXJpY2FsIHZhbHVlIGhhdmUgYmVlbiByZWNvZ25pemVkIGFzIHN0cmluZyAoZS5nLiAiMSw3MDcsNjM1IiwgIiQxLDM3MiAiKQoqIEluY29uc2lzdGVuY3kgb2YgY2F0ZWdvcmljYWwgdmFyaWFibGUgdmFsdWVzIGFuZCBjb2x1bW4gbmFtZXM6CiAgICAgICsgYGNhdGVnb3J5YCBpbiBZZWFybHkgU3BlbmRpbmcgYW5kIGBYLjFgIChUaGUgY29udGVudCBvZiB0aGlzIGNvbHVtbiByZXByZXNlbnRzIHNwZW5kaW5nIGNhdGVnb3J5IGFzIHdlbGwpIGluIE1vbnRobHkgU3BlbmRpbmcgaGF2ZSBkaWZmZXJlbnQgbnVtYmVyIG9mIGZhY3RvcnMgYW5kIGZvciB0aGUgc2FtZSBjYXRlZ29yeS4gRm9yIGV4YW1wbGUsIHdlIHN1c3Bpc2lvdXMgdGhhdCAiRWR1Y2F0aW9uIHJlbGF0ZWQiIGFuZCAiTWVkaWNhbC9FZHVjYXRpb24vV29ya2VycyBTcGVuZGluZyIgc2hvdWxkIHJlZmVyIHRvIHRoZSBzYW1lIGNhdGVnb3J5LiAKICAgICAgKyBJbiBzb21lIHRhYmxlIG1vbnRoIGlzIHJlcHJlc2VudGVkIGFzIGZpcnN0IHRocmVlIGxldHRlcnMgKGUuZy4gSmFuKSBhbmQgaW4gb3RoZXIgdGFibGUgaXMgcmVwcmVzZW50ZWQgYXMgZnVsbCBuYW1lIChlLmcuIEFQUklMKS4KICAgICAgKyBJbiBjb25zaXN0ZW5jeSBvZiB1cHBlci9sb3dlciBjYXNlIG9mIHN0cmluZ3MgKGUuZy4gYFllYXJgIGFuZCBgeWVhcmApCiogTWlzc2luZyB2YWx1ZXMKICAgICAgKyBJbiBvcmRlciB0byBzaG93IG1pc3NpbmcgdmFsdWUgbW9yZSBjbGVhcmx5LCB3ZSBwcmUtcHJvY2Vzc2VkIGRhdGEsIHRoZSBkZXRhaWwgYWJvdXQgaG93IHRvIGNsZWFuIGRhdGEgd2lsbCBiZSBkaXNjdXNzZWQgbGF0ZXIgaW4gTWFpbiBBbmFseXNpcyBwYXJ0LgogICAgICArIEFzIHdoYXQgYXJlIHNob3duIGluIHRoZSBncmFwaCBiZWxvdywgd2Ugb25seSBoYXZlIHNvbWUgbWlzc2luZyB2YWx1ZXMgaW4gR0RQIGRhdGEgZm9yIGNvdW50cmllcyB3ZSBhcmUgaW50ZXJlc3RlZC4gQnV0IHRoZSBtaXNzaW5nIHZhbHVlcyBhcmUgZWl0aGVyIGJlZm9yZSAxOTkwIG5vciBhZnRlciAyMDE2LCB3aGljaCB3b3VsZCBub3QgaW5mbHVlbmNlIG91ciBhbmFseXNpcy4KCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpjb3VudHJ5X3N0ciA8LSAnQXJnZW50aW5hfEF1c3RyYWxpYXxCcmF6aWx8Q2FuYWRhfENoaWxlfENoaW5hfENvbG9tYmlhfEZyYW5jZXxHZXJtYW55fEluZGlhfEl0YWx5fEphcGFufE1leGljb3xOZXRoZXJsYW5kc3xSdXNzaWF8U2F1ZGkgQXJhYmlhfFNvdXRoIEtvcmVhfFNpbmdhcG9yZXxTcGFpbnxTd2VkZW58U3dpdHplcmxhbmR8VGFpd2FufFVuaXRlZCBLaW5nZG9tfFVuaXRlZCBTdGF0ZXMnIAoKdGlkeV9udHRvX3NwZW5kX3kgPC0gcmF3X250dG9fc3BlbmRfeSAlPiUKICAgZ2F0aGVyKHhfeWVhciwgc3BlbmQsIC1yZWdpb24sIC10eXBlLCAtY2F0ZWdvcnkpICU+JSAKICAgc2VwYXJhdGUoeF95ZWFyLCBjKCJYIiwgIlllYXIiKSwgc2VwPSJYIikgJT4lIAogICBzZWxlY3QoLVgpICU+JSAKICAgc2VsZWN0KFJlZ2lvbj1yZWdpb24sIFR5cGU9dHlwZSwgQ2F0ZWdvcnk9Y2F0ZWdvcnksIFllYXI9WWVhcixTcGVuZD1zcGVuZCkgJT4lICAKICAgbXV0YXRlKFJlZ2lvbj1nc3ViKCJeXFxzK3xcXHMrJCIsICIiLCBSZWdpb24pKSAlPiUgCiAgIG11dGF0ZShNaXNzaW5nID0gaWZlbHNlKGlzLm5hKFNwZW5kKSwgInllcyIsICJubyIpLCBSZWdpb249dG9sb3dlcihSZWdpb24pLCBZZWFyPWZhY3RvcihZZWFyKSwgUmVnaW9uPWZhY3RvcihSZWdpb24pKQoKdGlkeV9udHRvX2luYm91bmRfbSA8LSByYXdfbnR0b19pbmJvdW5kX20gJT4lCiAgIG11dGF0ZShhcy5jaGFyYWN0ZXIoVE9UQUwuQVJSSVZBTFMpKSAlPiUgCiAgIGdhdGhlcihrZXksIHZhbCwgLXllYXIsIC1NT05USCkgJT4lCiAgIG11dGF0ZShBcnJpdmFsPWFzLm51bWVyaWMoZ3N1YignW14wLTldKycsICcnLCB2YWwpKSwgTW9udGg9bWF0Y2godG9sb3dlcihzdWJzdHIoTU9OVEgsIDEsIDMpKSwgdG9sb3dlcihtb250aC5hYmIpKSwga2V5PXRvbG93ZXIoZ3N1YignXFwuJywgJyAnLCBrZXkpKSwgWWVhcj15ZWFyKSAlPiUKICAgZmlsdGVyKCFncmVwbCgidG90YWwiLCBrZXkpKSAlPiUKICAgdW5pdGUoWWVhck1vbnRoLCB5ZWFyLCBNb250aCwgc2VwPSItIikgJT4lCiAgIHNlbGVjdChZZWFyLCBZZWFyTW9udGgsIE1peFJlZ2lvbj1rZXksIEluYm91bmQ9QXJyaXZhbCkgJT4lIAogICBtdXRhdGUoTWl4UmVnaW9uPXJlY29kZShNaXhSZWdpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAibGF0aW4gYW1lcmljYSAgZXhjbCBtZXhpY28gIj0ibGF0aW4gYW1lcmljYSBleGNsIG1leGljbyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJwcmMgIGV4Y2wgaGsgIj0iY2hpbmEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAicm9jICB0YWl3YW4gIj0idGFpd2FuIikpICU+JSAKICAgbXV0YXRlKE1pc3NpbmcgPSBpZmVsc2UoaXMubmEoSW5ib3VuZCksICJ5ZXMiLCAibm8iKSwgWWVhcj1mYWN0b3IoWWVhciksIERhdGU9YXMueWVhcm1vbihZZWFyTW9udGgpLCBNaXhSZWdpb249ZmFjdG9yKE1peFJlZ2lvbikpICU+JSAKICAgYXJyYW5nZShNaXhSZWdpb24sIERhdGUpCgp0aWR5X250dG9fb3V0Ym91bmRfbSA8LSByYXdfbnR0b19vdXRib3VuZF9tICU+JSAKICAgZ2F0aGVyKE1vbnRoLCBPdXRib3VuZCwgLVllYXIsIC1SZWdpb25zKSAlPiUgCiAgIG11dGF0ZShPdXRib3VuZD1hcy5udW1lcmljKGdzdWIoJ1teMC05XSsnLCAnJywgT3V0Ym91bmQpKSwgTW9udGg9bWF0Y2goTW9udGgsIG1vbnRoLmFiYiksIE1peFJlZ2lvbj10b2xvd2VyKGdzdWIoJ1xcKFthLXpBLVowLTldK1xcKScsICcnLCBSZWdpb25zKSksIHllYXI9WWVhcikgJT4lIAogICBtdXRhdGUoTWl4UmVnaW9uPWdzdWIoIl5cXHMrfFxccyskIiwgIiIsIE1peFJlZ2lvbikpICU+JSAKICAgZmlsdGVyKCFncmVwbCgiYWlyIiwgTWl4UmVnaW9uKSwgIU1peFJlZ2lvbj09J3RvdGFsIG92ZXJzZWFzJywgIU1peFJlZ2lvbj09J25vcnRoIGFtZXJpY2EnLCAhTWl4UmVnaW9uPT0nZ3JhbmQgdG90YWwnKSAlPiUgCiAgIHVuaXRlKFllYXJNb250aCwgeWVhciwgTW9udGgsIHNlcD0iLSIpICU+JSAKICAgbXV0YXRlKFJlZ2lvbj1yZWNvZGUoTWl4UmVnaW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgImNhcmliYmVhbiI9ImxhdGluIGFtZXJpY2EgZXhjbCBtZXhpY28iLAogICAgICAgICAgICAgICAgICAgICAgICAiY2VudHJhbCBhbWVyaWNhIj0ibGF0aW4gYW1lcmljYSBleGNsIG1leGljbyIsCiAgICAgICAgICAgICAgICAgICAgICAgICJzb3V0aCBhbWVyaWNhIj0ibGF0aW4gYW1lcmljYSBleGNsIG1leGljbyIpKSAlPiUgCiAgIG11dGF0ZShNaXNzaW5nPWlmZWxzZShpcy5uYShPdXRib3VuZCksICJ5ZXMiLCAibm8iKSwgWWVhcj1mYWN0b3IoWWVhciksIERhdGU9YXMueWVhcm1vbihZZWFyTW9udGgpLCBNaXhSZWdpb249ZmFjdG9yKE1peFJlZ2lvbiksIFJlZ2lvbj1mYWN0b3IoUmVnaW9uKSkgJT4lIAogICBzZWxlY3QoUmVnaW9uLCBNaXhSZWdpb24sIFllYXIsIERhdGUsIE1pc3NpbmcsIE91dGJvdW5kKSAlPiUgCiAgIGFycmFuZ2UoUmVnaW9uLCBNaXhSZWdpb24sIERhdGUpCgoKdGlkeV93Yl9nZHAgPC0gcmF3X3diX2dkcCAlPiUgCiAgIHNlbGVjdCgtSW5kaWNhdG9yLk5hbWUsIC1JbmRpY2F0b3IuQ29kZSwgLVgpICU+JSAKICAgZ2F0aGVyKHhfeWVhciwgR0RQLCAtQ291bnRyeS5OYW1lLCAtQ291bnRyeS5Db2RlKSAlPiUgCiAgIGZpbHRlcihncmVwbChjb3VudHJ5X3N0ciwgQ291bnRyeS5OYW1lKSkgJT4lIAogICBzZXBhcmF0ZSh4X3llYXIsIGMoIlgiLCAiWWVhciIpLCBzZXA9IlgiKSAlPiUgCiAgIHNlbGVjdCgtWCkgJT4lIAogICBzZWxlY3QoQ291bnRyeU5hbWU9Q291bnRyeS5OYW1lLCBDb3VudHJ5Q29kZT1Db3VudHJ5LkNvZGUsIFllYXI9WWVhciwgR0RQPUdEUCkgJT4lIAogICAjIGZpbHRlcih5ZWFyPjE5OTkpICU+JSAKICAgbXV0YXRlKE1pc3NpbmcgPSBpZmVsc2UoaXMubmEoR0RQKSwgInllcyIsICJubyIpKQpgYGAKCgpgYGB7cn0KZ2dwbG90KHRpZHlfbnR0b19zcGVuZF95LCBhZXMoeD1ZZWFyLCB5PVJlZ2lvbiwgZmlsbCA9IE1pc3NpbmcpKSArCiAgIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpICsgCiAgIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUpICsKICAgZ2d0aXRsZSgiTWlzc2luZyBWYWx1ZSBvZiBOVFRPIFllYXJseSBTcGVuZGluZyBEYXRhIikgKwogICB0aGVtZV9saW5lZHJhdygpCmBgYAoKYGBge3J9CmdncGxvdCh0aWR5X250dG9faW5ib3VuZF9tLCBhZXMoeD1EYXRlLCB5PU1peFJlZ2lvbiwgZmlsbCA9IE1pc3NpbmcpKSArCiAgIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpICsgCiAgIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUpICsKICAgZ2d0aXRsZSgiTWlzc2luZyBWYWx1ZSBvZiBOVFRPIEluYm91bmQgRGF0YSIpICsKICAgdGhlbWVfbGluZWRyYXcoKSArCiAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCkpCmBgYAoKYGBge3J9CmdncGxvdCh0aWR5X250dG9fb3V0Ym91bmRfbSwgYWVzKHg9RGF0ZSwgeT1NaXhSZWdpb24sIGZpbGwgPSBNaXNzaW5nKSkgKwogICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArIAogICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKSArCiAgIGdndGl0bGUoIk1pc3NpbmcgVmFsdWUgb2YgTlRUTyBPdXRib3VuZCBEYXRhIikgKwogICB0aGVtZV9saW5lZHJhdygpICsKICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTkwKSkKYGBgCgoKYGBge3IgZmlnLmhlaWdodD0zLCBmaWcud2lkdGg9NX0KZ2dwbG90KHRpZHlfd2JfZ2RwLCBhZXMoeD1ZZWFyLCB5PUNvdW50cnlOYW1lLCAgZmlsbCA9IE1pc3NpbmcpKSArCiAgIGdlb21fdGlsZShjb2xvciA9ICJ3aGl0ZSIpICsgCiAgIHNjYWxlX2ZpbGxfdmlyaWRpcyhkaXNjcmV0ZSA9IFRSVUUpICsKICAgZ2d0aXRsZSgiTWlzc2luZyBWYWx1ZSBvZiBBbGwgSW50ZXJlc3RlZCBDb3VudHJpZXMgKDE5NjAtMjAxNikiKSArCiAgIHRoZW1lX2xpbmVkcmF3KCkgKwogICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTApKSAKYGBgCgojIyBFeGVjdXRpdmUgU3VtbWFyeQo+IFByb3ZpZGUgYSBzaG9ydCBub250ZWNobmljYWwgc3VtbWFyeSBvZiB0aGUgbW9zdCByZXZlYWxpbmcgZmluZGluZ3Mgb2YgeW91ciBhbmFseXNpcyB3aXRoIG5vIG1vcmUgdGhhbiAzIHN0YXRpYyBncmFwaHMgb3Igb25lIGludGVyYWN0aXZlIGdyYXBoIChvciBsaW5rKSwgd3JpdHRlbiBmb3IgYSBub250ZWNobmljYWwgYXVkaWVuY2UuIAo+IFRoZSBsZW5ndGggc2hvdWxkIGJlIGFwcHJveGltYXRlbHkgMiBwYWdlcyAoaWYgd2Ugd2VyZSB1c2luZyBwYWdlcy4uLikgRG8gbm90IHNob3cgY29kZSwgYW5kIHRha2UgZXh0cmEgY2FyZSB0byBjbGVhbiB1cCB5b3VyIGdyYXBocywgZW5zdXJpbmcgdGhhdCBiZXN0IHByYWN0aWNlcyBmb3IgcHJlc2VudGF0aW9uIGFyZSBmb2xsb3dlZC4KCuKAoiBOb3RlOiB0aGUgdGlwcyBiZWxvdyBhcmUgbm90IGludGVuZGVkIHRvIGJlIGEgY29tcGxldGUgbGlzdCBvZiBldmVyeXRoaW5nIHdlJ3ZlIGNvdmVyZWQgdGhpcyBzZW1lc3RlciBvbiBkZXNpZ25pbmcgYSBzdWNjZXNzZnVsIGdyYXBoLiBJdCdzIG1lYW50IHRvIGhlbHAgeW91IGF2b2lkIHNvbWUgY29tbW9uIHByb2JsZW1zLgoK4oCiIFRpdGxlLCBheGlzIGxhYmVscywgdGljayBtYXJrIGxhYmVscywgYW5kIGxlZ2VuZHMgc2hvdWxkIGJlIGNvbXByZWhlbnNpYmxlIChlYXN5IHRvIHVuZGVyc3RhbmQpIGFuZCBsZWdpYmxlIChlYXN5IHRvIHJlYWQgLyBkZWNpcGhlcikuCgrigKIgVGljayBtYXJrcyBzaG91bGQgbm90IGJlIGxhYmVsZWQgaW4gc2NpZW50aWZpYyBub3RhdGlvbiBvciB3aXRoIGxvbmcgc3RyaW5ncyBvZiB6ZXJvcywgc3VjaCBhcyAzMDAwMDAwMDAwLiBJbnN0ZWFkLCBjb252ZXJ0IHRvIHNtYWxsZXIgbnVtYmVycyBhbmQgY2hhbmdlIHRoZSB1bml0czogMzAwMDAwMDAwMCBiZWNvbWVzICIzIiBhbmQgdGhlIGF4aXMgbGFiZWwgImJpbGxpb25zIG9mIHZpZXdzIi4KCuKAoiBVbml0cyBzaG91bGQgYmUgaW50dWl0aXZlIChFeHRyZW1lIGV4YW1wbGU6IGFuIGF4aXMgbGFiZWxlZCBpbiBtb250aC9kYXkveWVhciBmb3JtYXQgaXMgaW50dWl0aXZlLCBvbmUgbGFiZWxlZCBpbiBzZWNvbmRzIHNpbmNlIEphbnVhcnkgMSwgMTk3MCBpcyBub3QuKQoK4oCiIFRoZSBmb250IHNpemUgc2hvdWxkIGJlIGxhcmdlIGVub3VnaCB0byByZWFkIGNsZWFybHkuIFRoZSBkZWZhdWx0IGluIGdncGxvdDIgaXMgZ2VuZXJhbGx5IHRvbyBzbWFsbC4gWW91IGNhbiBlYXNpbHkgY2hhbmdlIGl0IGJ5IHBhc3NpbmcgdGhlIGJhc2UgZm9udCBzaXplIHRvIHRoZSB0aGVtZSwgc3VjaCBhcyArIHRoZW1lX2dyZXkoMTYpLiAoVGhlIGRlZmF1bHQgYmFzZSBmb250IHNpemUgaXMgMTEuKQoK4oCiIFRoZSBvcmRlciBvZiBpdGVtcyBvbiB0aGUgYXhlcyBhbmQgbGVnZW5kcyBpcyBsb2dpY2FsLiAoQWxwaGFiZXRpY2FsIGlzIG9mdGVuIG5vdCBsb2dpY2FsLikKCuKAoiBDb2xvcnMgc2hvdWxkIGJlIGNvbG9yIHZpc2lvbiBkZWZpY2llbmN5IGZyaWVuZGx5LgoK4oCiIElmIGEgbGVnZW5kIGlzIHRha2luZyB1cCB0b28gbXVjaCBzcGFjZSBvbiB0aGUgcmlnaHQsIG1vdmUgaXQgdG8gdGhlIGJvdHRvbS4KCuKAoiBJZiBjYXRlZ29yaWNhbCB2YXJpYWJsZSBsZXZlbHMgYXJlIGxvbmcsIHNldCB1cCB0aGUgZ3JhcGggc28gdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGlzIG9uIHRoZSB5LWF4aXMgYW5kIHRoZSBuYW1lcyBhcmUgaG9yaXpvbnRhbC4gQSBiZXR0ZXIgb3B0aW9uLCBpZiBwb3NzaWJsZSwgaXMgdG8gc2hvcnRlbiB0aGUgbmFtZXMgb2YgdGhlIGxldmVscy4KCuKAoiBOb3QgYWxsIEVEQSBncmFwaHMgbGVuZCB0aGVtc2VsdmVzIHRvIHByZXNlbnRhdGlvbiwgZWl0aGVyIGJlY2F1c2UgdGhlIGdyYXBoIGZvcm0gaXMgaGFyZCB0byB1bmRlcnN0YW5kIHdpdGhvdXQgcHJhY3RpY2Ugb3IgaXQncyBub3Qgd2VsbCBsYWJlbGVkLiBUaGUgbGFiZWxpbmcgcHJvYmxlbSBjYW4gYmUgc29sdmVkIGJ5IGFkZGluZyB0ZXh0IGluIGFuIGltYWdlIGVkaXRvci4gVGhlIGRvd25zaWRlIGlzIHRoYXQgaXQgaXMgbm90IHJlcHJvZHVjaWJsZS4gSWYgeW91IHdhbnQgdG8gZ28gdGhpcyByb3V0ZSwgUGFpbnRicnVzaCBpcyBhIGZyZWUgYW5kIHNpbXBsZSBiaXRtYXAgaW1hZ2UgZWRpdG9yIGZvciB0aGUgTWFjOiBodHRwczovL3BhaW50YnJ1c2guc291cmNlZm9yZ2UuaW8vIFRoZXJlIGFyZSBtYW55IG90aGVyIG9wdGlvbnMuCgrigKIgRXJyIG9uIHRoZSBzaWRlIG9mIHNpbXBsaWNpdHkuIERvbid0LCBmb3IgZXhhbXBsZSwgb3ZlcnVzZSBjb2xvciB3aGVuIGl0J3Mgbm90IG5lY2Vzc2FyeS4gQXNrIHlvdXJzZWxmOiBkb2VzIGNvbG9yIG1ha2UgdGhpcyBncmFwaCBhbnkgY2xlYXJlcj8gSWYgaXQgZG9lc24ndCwgbGVhdmUgaXQgb3V0LgoK4oCiIFRlc3QgeW91ciBncmFwaHMgb24gbm9udGVjaG5pY2FsIGZyaWVuZHMgYW5kIGZhbWlseSBhbmQgYXNrIGZvciBmZWVkYmFjay4KCiMjIE1haW4gQW5hbHlzaXMKPiBQcm92aWRlIGEgZGV0YWlsZWQsIHdlbGwtb3JnYW5pemVkIGRlc2NyaXB0aW9uIG9mIHlvdXIgZmluZGluZ3MsIGluY2x1ZGluZyB0ZXh0dWFsIGRlc2NyaXB0aW9uLCBncmFwaHMsIGFuZCBjb2RlLiBZb3VyIGZvY3VzIHNob3VsZCBiZSBvbiBib3RoIHRoZSByZXN1bHRzIGFuZCB0aGUgcHJvY2Vzcy4gSW5jbHVkZSwgYXMgcmVhc29uYWJsZSBhbmQgcmVsZXZhbnQsIGFwcHJvYWNoZXMgdGhhdCBkaWRuJ3Qgd29yaywgY2hhbGxlbmdlcywgdGhlIGRhdGEgY2xlYW5pbmcgcHJvY2VzcywgZXRjLgoK4oCiIFRoZSBndWlkZWxpbmVzIGZvciB0aGUgRXhlY3V0aXZlIFN1bW1hcnkgYWJvdmUgZG8gTk9UIGFwcGx5IHRvIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMuIFlvdXIgbWFpbiBjb25jZXJuIGlzIGRlc2lnbmluZyBncmFwaHMgdGhhdCByZXZlYWwgcGF0dGVybnMgYW5kIHRyZW5kcy4KCuKAoiBBcyBub3RlZCBpbiBIbWsgIzQsIGRvIG5vdCB1c2UgY2lyY2xlcywgdGhhdCBpczogYnViYmxlcywgcGllIGNoYXJ0cywgb3IgcG9sYXIgY29vcmRpbmF0ZXMuCgrigKIgVXNlIHN0YWNrZWQgYmFyIGNoYXJ0cyBzcGFyaW5nbHkuIFRyeSBncm91cGVkIGJhciBjaGFydHMgYW5kIGZhY2V0aW5nIGFzIGFsdGVybmF0aXZlcywgYW5kIG9ubHkgY2hvb3NlIHN0YWNrZWQgYmFyIGNoYXJ0cyBpZiB0aGV5IHRydWx5IGRvIGEgYmV0dGVyIGpvYiB0aGFuIHRoZSBhbHRlcm5hdGl2ZXMgZm9yIG9ic2VydmluZyBwYXR0ZXJucy4KCgojIyMgRGF0YSBDbGVhbmluZwoKU2luY2UgdGhlIGRhdGEgaXMgdmVyeSBtZXNzeSwgd2UgcHV0IG1hbnkgZWZmb3J0IG9uIGNsZWFuaW5nIGFuZCBleHRyYWN0IHVzZWZ1bCBpbmZvbWF0aW9uIGZvciBhbmFseXNpcy4gCgoxLiBDb252ZXJ0IHRvIGNvcnJlY3QgdHlwZQoyLiBDb25zb2xpZGF0ZSBuYW1lLCByZWdpb24sIGRhdGUKCgpKb2luIHNhbWUgcmVnaW9uCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcmVnaW9uX3N0ciA8LSAiYWZyaWNhfGFzaWF8Y2FuYWRhfGxhdGluIGFtZXJpY2EgKGV4Y2wgbWV4aWNvKXxldXJvcGV8bWV4aWNvfG1pZGRsZSBlYXN0fG9jZWFuaWEiCgppbmJvdW5kX3JlZ2lvbiA8LSB0aWR5X250dG9faW5ib3VuZF9tICU+JSAKICAgZmlsdGVyKGdyZXBsKHJlZ2lvbl9zdHIsIE1peFJlZ2lvbikpICU+JSAKICAgc2VsZWN0KFJlZ2lvbj1NaXhSZWdpb24sIFllYXIsIERhdGUsIEluYm91bmQpICU+JSAKICAgZ3JvdXBfYnkoUmVnaW9uLCBZZWFyLCBEYXRlKSAlPiUgCiAgIHN1bW1hcmlzZShUb3RhbEluYm91bmQ9c3VtKEluYm91bmQpKSAlPiUgCiAgIHVuZ3JvdXAKCm91dGJvdW5kX3JlZ2lvbiA8LSB0aWR5X250dG9fb3V0Ym91bmRfbSAlPiUgCiAgIHNlbGVjdChSZWdpb24sIFllYXIsIERhdGUsIE91dGJvdW5kKSAlPiUgCiAgIGdyb3VwX2J5KFJlZ2lvbiwgWWVhciwgRGF0ZSkgJT4lIAogICBzdW1tYXJpc2UoVG90YWxPdXRib3VuZD1zdW0oT3V0Ym91bmQpKSAlPiUgCiAgIHVuZ3JvdXAKCnJlZ2lvbmFsX3RyYXZlbCA8LSBpbm5lcl9qb2luKGluYm91bmRfcmVnaW9uLCBvdXRib3VuZF9yZWdpb24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBieT1jKCJSZWdpb24iPSJSZWdpb24iLCAiWWVhciI9IlllYXIiLCAiRGF0ZSI9IkRhdGUiKSkKCmBgYAoKCiMjIyBDaGFsbGVuZ2VzCgpUaGVyZSBhcmUgc2V2ZXJhbCBjaGFsbGVuZ2VzIGluIG91ciBwcm9qZWN0OgoKMS4gRHVlIHRvIHRoZSBwcm9ibGVtcyBpbiB0aGUgZGF0YSBzZXQgc3VjaCBhcyBpbmNvbnNpc3RlbmN5LCB3ZSBoYXZlIHRvIHNwZW5kIG11Y2ggdGltZSBpbiBjbGVhbmluZyBhbmQgcmUtb3JnYW5pemluZyBpdCwgd2hpY2ggbWFrZXMgdGhlIHdvcmsgdGVkaW91cyBhbmQgbGFib3Jpb3VzLiAKMi4gV2UgbmVlZCBjb3VudHJ5IGxldmVsIGRhdGEgaW4gc29tZSBncmFwaHM7IGhvd2V2ZXIsIHdoYXQgd2UgY2FuIGFjcXVpcmUgZnJvbSB0aGUgZGF0YXNldCBpcyByZWdpb24gbGV2ZWwuIEluIHRoYXQgY2FzZSwgd2UgaGF2ZSB0byBwcm9qZWN0IHRoZSBkYXRhIG9udG8gdGhlIHdob2xlIHJlZ2lvbiwgd2hpY2ggbWFrZXMgdGhlIGFuYWx5c2lzIG5vdCBjb21wcmVoZW5zaXZlIGFuZCBkZXRhaWxlZC4KMy4gU2hpbnkgaXMgYSBncmVhdCB0b29sIGZvciBjcmVhdGluZyBpbnRlcmFjdGl2ZSBkYXRhIHZpc3VhbGl6YXRpb25zIGluIFI7IGhvd2V2ZXIsIHdlIGRvIG5vdCBoYXZlIG11Y2ggZXhwZXJpZW5jZSBpbiBpdCwgYW5kIHRoZXJlZm9yZSBoYXZlIHRvIHNwZW5kIHRpbWUgbGVhcm5pbmcgaXQsIHdoaWNoIGlzIG5vdCBlYXN5IGluIHN1Y2ggYSBzaG9ydCB0aW1lLgoKCiMjIyBBbmFseXNpcwoKIyMjIyBUcmF2ZWwgYW5kIFRvdXJpc20gQW5hbHlzaXMKCmBgYHtyIGZpZy5oZWlnaHQ9M30KcmVnaW9uYWxfdHJhdmVsICU+JSAKICAgc2VsZWN0KFllYXIsIFRvdGFsSW5ib3VuZCwgVG90YWxPdXRib3VuZCkgJT4lIAogICBncm91cF9ieShZZWFyKSAlPiUgCiAgIHN1bW1hcmlzZShUb3RhbEluYm91bmQ9c3VtKFRvdGFsSW5ib3VuZCksIFRvdGFsT3V0Ym91bmQ9c3VtKFRvdGFsT3V0Ym91bmQpKSAlPiUgCiAgIHBsb3RfbHkoeCA9IH5ZZWFyLCB5ID0gflRvdGFsSW5ib3VuZCwgdHlwZSA9ICdiYXInLCBuYW1lID0gJ0luYm91bmQnLCBtYXJrZXIgPSBsaXN0KGNvbG9yID0gJ3JnYig1NSwgODMsIDEwOSknKSkgJT4lCmFkZF90cmFjZSh5ID0gflRvdGFsT3V0Ym91bmQsIG5hbWUgPSAnT3V0Ym91bmQnLCBtYXJrZXIgPSBsaXN0KGNvbG9yID0gJ3JnYigyNiwgMTE4LCAyNTUpJykpICU+JQpsYXlvdXQodGl0bGUgPSAnWWVhcmx5IEluYm91bmQgYW5kIE91dGJvdW5kJywKICAgICAgeGF4aXMgPSBsaXN0KAogICAgICAgIHRpdGxlID0gIiIsCiAgICAgICAgdGlja2ZvbnQgPSBsaXN0KAogICAgICAgICAgc2l6ZSA9IDE0LAogICAgICAgICAgY29sb3IgPSAncmdiKDEwNywgMTA3LCAxMDcpJykpLAogICAgICB5YXhpcyA9IGxpc3QoCiAgICAgICAgdGl0bGUgPSAnTnVtYmVyIG9mIFBlb3BsZScsCiAgICAgICAgdGl0bGVmb250ID0gbGlzdCgKICAgICAgICAgIHNpemUgPSAxNiwKICAgICAgICAgIGNvbG9yID0gJ3JnYigxMDcsIDEwNywgMTA3KScpLAogICAgICAgIHRpY2tmb250ID0gbGlzdCgKICAgICAgICAgIHNpemUgPSAxNCwKICAgICAgICAgIGNvbG9yID0gJ3JnYigxMDcsIDEwNywgMTA3KScpKSwKICAgICAgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICdoJywgeCA9IDAsIHkgPSAxLCAKICAgICAgICAgICAgICAgICAgICBiZ2NvbG9yID0gJ3JnYmEoMjU1LCAyNTUsIDI1NSwgMCknLCBib3JkZXJjb2xvciA9ICdyZ2JhKDI1NSwgMjU1LCAyNTUsIDApJyksCiAgICAgIGJhcm1vZGUgPSAnZ3JvdXAnLCBiYXJnYXAgPSAwLjE1KQpgYGAKCgpUaGUgVW5pdGVkIFN0YXRlcyBpcyBvbmUgb2YgdGhlIGxhcmdlc3QgZGVzdGluYXRpb25zIGZvciB2aXNpdG9ycyBhbmQgaGFzIGEgbGFyZ2UgYW1vdW50IG91dGJvdW5kIGpvdXJuZXlzIGFzIHdlbGwuIFRoZSBudW1iZXJzIG9mIGluYm91bmQgYW5kIG91dGJvdW5kIGhhdmUgaW5jcmVhc2VkIGEgbG90IGZyb20gMjAwOSB0byAyMDEwLiBCZXR3ZWVuIDIwMTAgdG8gMjAxMywgdGhlIG51bWJlciBvZiBpbnRlcm5hdGlvbmFsIHZpc2l0b3JzIHJhaXNlZCBhIGxpdHRsZSBiaXQgZWFjaCB5ZWFyIGhvd2V2ZXIgdGhlIGFtb3VuZCBvZiBvdXRib3VuZCBpcyBraW5kIG9mIHN0YWJsZS4gU2luY2UgMjAxMywgYm90aCBvZiB0aGVtIGdyb3duIGEgbG90IGFuZCBmaW5hbGx5IGFjaGlldmVkIDc3LjUgbWlsbGlvbiBpbnRlcm5hdGlvbmFsIHZpc2l0YXRpb25zIGFuZCA4NS42IG1pbGxpb24gb3V0Ym91bmQgdHJhdmVsbGVycyBpbiAyMDE1LiAKCk5hdHVyYWxseSB3ZSBzdGFydCB3b25kZXJpbmcgd2hhdCBhcmUgdGhlIG1vc3QgcG9wdWxhciBkZXN0aW5hdGlvbiBmb3IgYW1lcmljYW5zIGFuZCB3aGVyZSBhcmUgdGhlc2UgaW50ZXJuYXRpb25hbCB2aXN0b3JzIGNvbWUgZnJvbT8gVG8gYW5zd2VyIHRoZXNlIHF1ZXN0aW9ucywgd2UgYnJlYWsgZG93biB0aGUgZ3JhcGggaW50byBzbWFsbGVyIHJlZ2lvbnMuIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcDEgPC0gaW5ib3VuZF9yZWdpb24gJT4lIAogICBzcHJlYWQoUmVnaW9uLCBUb3RhbEluYm91bmQpICU+JSAKICAgZmlsdGVyKERhdGU+JzIwMDgtMTEnKSAlPiUgCiAgIHBsb3RfbHkoeCA9IH5hcy5QT1NJWGN0KERhdGUpKSAlPiUKICAgYWRkX3RyYWNlKHk9fmFmcmljYSwgbmFtZT0nYWZyaWNhJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0iZ3JheSIsIHdpZHRoID0gMSkpICU+JQogICBhZGRfdHJhY2UoeT1+YXNpYSwgbmFtZT0nYXNpYScsIG1vZGU9J2xpbmVzJywgbGluZSA9IGxpc3QoY29sb3I9InJlZCIsIHdpZHRoID0gMSkpICU+JQogICBhZGRfdHJhY2UoeT1+Y2FuYWRhLCBuYW1lPSdjYW5hZGEnLCBtb2RlPSdsaW5lcycsIGxpbmUgPSBsaXN0KGNvbG9yPSJvcmFuZ2UiLCB3aWR0aCA9IDEpKSAlPiUKICAgYWRkX3RyYWNlKHk9fmV1cm9wZSwgbmFtZT0nZXVyb3BlJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0icGluayIsIHdpZHRoID0gMSkpICU+JQogICBhZGRfdHJhY2UoeT1+YGxhdGluIGFtZXJpY2EgZXhjbCBtZXhpY29gLCBuYW1lPSdsYXRpbiBhbWVyaWNhIGV4Y2wgbWV4aWNvJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0iZ3JlZW4iLCB3aWR0aCA9IDEpKSAlPiUKICAgYWRkX3RyYWNlKHk9fm1leGljbywgbmFtZT0nbWV4aWNvJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0icHVycGxlIiwgd2lkdGggPSAxKSkgJT4lCiAgIGFkZF90cmFjZSh5PX5gbWlkZGxlIGVhc3RgLCBuYW1lPSdtaWRkbGUgZWFzdCcsIG1vZGU9J2xpbmVzJywgbGluZSA9IGxpc3QoY29sb3I9ImJsYWNrIiwgd2lkdGggPSAxKSkgJT4lCiAgIGFkZF90cmFjZSh5PX5vY2VhbmlhLCBuYW1lPSdvY2VhbmlhJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0iYmx1ZSIsIHdpZHRoID0gMSkpIAoKcDIgPC0gb3V0Ym91bmRfcmVnaW9uICU+JSBzcHJlYWQoUmVnaW9uLCBUb3RhbE91dGJvdW5kKSAlPiUgCiAgIHBsb3RfbHkoeCA9IH5hcy5QT1NJWGN0KERhdGUpKSAlPiUKICAgYWRkX3RyYWNlKHk9fmFmcmljYSwgbmFtZT0nYWZyaWNhJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0iZ3JheSIsIHdpZHRoID0gMSksIHNob3dsZWdlbmQ9RikgJT4lCiAgIGFkZF90cmFjZSh5PX5hc2lhLCBuYW1lPSdhc2lhJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0icmVkIiwgd2lkdGggPSAxKSwgc2hvd2xlZ2VuZD1GKSAlPiUKICAgYWRkX3RyYWNlKHk9fmNhbmFkYSwgbmFtZT0nY2FuYWRhJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0ib3JhbmdlIiwgd2lkdGggPSAxKSwgc2hvd2xlZ2VuZD1GKSAlPiUKICAgYWRkX3RyYWNlKHk9fmV1cm9wZSwgbmFtZT0nZXVyb3BlJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0icGluayIsIHdpZHRoID0gMSksIHNob3dsZWdlbmQ9RikgJT4lCiAgIGFkZF90cmFjZSh5PX5gbGF0aW4gYW1lcmljYSBleGNsIG1leGljb2AsIG5hbWU9J2xhdGluIGFtZXJpY2EgZXhjbCBtZXhpY28nLCBtb2RlPSdsaW5lcycsIGxpbmUgPSBsaXN0KGNvbG9yPSJncmVlbiIsIHdpZHRoID0gMSksIHNob3dsZWdlbmQ9RikgJT4lCiAgIGFkZF90cmFjZSh5PX5tZXhpY28sIG5hbWU9J21leGljbycsIG1vZGU9J2xpbmVzJywgbGluZSA9IGxpc3QoY29sb3I9InB1cnBsZSIsIHdpZHRoID0gMSksIHNob3dsZWdlbmQ9RikgJT4lCiAgIGFkZF90cmFjZSh5PX5gbWlkZGxlIGVhc3RgLCBuYW1lPSdtaWRkbGUgZWFzdCcsIG1vZGU9J2xpbmVzJywgbGluZSA9IGxpc3QoY29sb3I9ImJsYWNrIiwgd2lkdGggPSAxKSwgc2hvd2xlZ2VuZD1GKSAlPiUKICAgYWRkX3RyYWNlKHk9fm9jZWFuaWEsIG5hbWU9J29jZWFuaWEnLCBtb2RlPSdsaW5lcycsIGxpbmUgPSBsaXN0KGNvbG9yPSJibHVlIiwgd2lkdGggPSAxKSwgc2hvd2xlZ2VuZD1GKQoKc3VicGxvdChwMSwgcDIsIG5yb3dzPTIsIHNoYXJlWD1UKSAlPiUKICBsYXlvdXQodGl0bGUgPSAiSW5ib3VuZCB2LnMuIE91dGJvdW5kIiwKICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIkluYm91bmQiKSwKICAgICAgICAgeWF4aXMyID0gbGlzdCh0aXRsZSA9ICJPdXRib3VuZCIpLAogICAgICAgICBsZWdlbmQgPSBsaXN0KG9yaWVudGF0aW9uID0gJ2gnKQogICAgICAgICApCmBgYAoKQWZ0ZXIgc2VwYXJhdGluZyBlYWNoIHJlZ2lvbiBvdXQsIHdlIG9ic2VydmVkIHNldmVyYWwgdGhpbmdzOgoKLSBNb3N0IG9mIHRoZSBpbnRlcm5hdGlvbmFsIHRyYXZlbGxlcnMgYXJlIGNvbWUgZnJvbSBDYW5hZGEsIE1leGljbywgRXVyb3BlLCBhbmQgQXNpYS4gCi0gTWV4aWNvLCBDYW5hZGEsIEV1cm9wZSwgYW5kIExhdGluIEFtZXJpY2EgZXhjZXB0IE1leGljbyBhcmUgdGhlIHRvcCBkZXN0aW5hdGlvbnMgZm9yIGFtZXJpY2Fucy4gCi0gU2Vhc29uYWxpdHkgZXhpc3RzIGluIGVhY2ggbGluZS4gVXN1YWxseSBwZWFrIGlzIHJlYWNoZWQgaW4gc3VtbWVyLiBGb3IgZXhhbXBsZSwgZXZlcnkgeWVhciBvZiBKdWx5LCB0aGUgbnVtYmVyIG9mIGNhbmFkYSB2aXN0b3JzIHJlYWNoZXMgaXRzIGhpZ2hlc3QgcGVhayBvZiB0aGUgeWVhci4KLSBBIGJvb20gaW4gYW1vdW50IG9mIHZpc2l0b3JzIGZyb20gTGF0aW4gQW1lcmljYSBleGNlcHQgTWV4aWNvIGluIHRoZSBiZWdpbmluZyBvZiAyMDE0IGFuZCBhIGJvb20gaW4gYW1vdW50IG9mIHBlb3BsZSB0cmF2ZWwgdG8gTWV4aWNvIGluIHRoZSBzdGFydCBvZiAyMDEwLgoKV2UgZnVydGhlciBkcmF3cyBpbmJvdW5kIGFuZCBvdXRib3VuZCBwZXIgcmVnaW9uIHRvIGJldHRlciBleHBsb3JlIHRoZSBoaWRkZW4gcGF0dGVybiBpbmRpdmlkdWFsbHkuCgpgYGB7ciBmaWcuaGVpZ2h0PTIwLCBtZXNzYWdlPUZBTFNFfQpwMSA8LSByZWdpb25hbF90cmF2ZWwgJT4lIAogICBmaWx0ZXIoUmVnaW9uPT0nYWZyaWNhJykgJT4lIAogICBwbG90X2x5KHggPSB+YXMuUE9TSVhjdChEYXRlKSwgaGVpZ2h0ID0gMTAwMCkgJT4lCiAgIGFkZF90cmFjZSh5PX5Ub3RhbEluYm91bmQsIHR5cGU9InNjYXR0ZXIiLCBuYW1lPSdJbmJvdW5kJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0iZ3JheSIsIHdpZHRoID0gMSkpICU+JQogICBhZGRfdHJhY2UoeT1+VG90YWxPdXRib3VuZCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J091dGJvdW5kJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0iYmx1ZSIsIHdpZHRoID0gMSkpICU+JSAKICAgbGF5b3V0KGF1dG9zaXplPUYpCgpwMiA8LSByZWdpb25hbF90cmF2ZWwgJT4lIAogICBmaWx0ZXIoUmVnaW9uPT0nYXNpYScpICU+JSAKICAgcGxvdF9seSh4ID0gfmFzLlBPU0lYY3QoRGF0ZSkpICU+JQogICBhZGRfdHJhY2UoeT1+VG90YWxJbmJvdW5kLCB0eXBlPSJzY2F0dGVyIiwgbmFtZT0nSW5ib3VuZCcsIG1vZGU9J2xpbmVzJywgbGluZSA9IGxpc3QoY29sb3I9ImdyYXkiLCB3aWR0aCA9IDEpLCBzaG93bGVnZW5kPUYpICU+JQogICBhZGRfdHJhY2UoeT1+VG90YWxPdXRib3VuZCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J091dGJvdW5kJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0iYmx1ZSIsIHdpZHRoID0gMSksIHNob3dsZWdlbmQ9RikKCnAzIDwtIHJlZ2lvbmFsX3RyYXZlbCAlPiUgCiAgIGZpbHRlcihSZWdpb249PSdjYW5hZGEnKSAlPiUgCiAgIHBsb3RfbHkoeCA9IH5hcy5QT1NJWGN0KERhdGUpKSAlPiUKICAgYWRkX3RyYWNlKHk9flRvdGFsSW5ib3VuZCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J0luYm91bmQnLCBtb2RlPSdsaW5lcycsIGxpbmUgPSBsaXN0KGNvbG9yPSJncmF5Iiwgd2lkdGggPSAxKSwgc2hvd2xlZ2VuZD1GKSAlPiUKICAgYWRkX3RyYWNlKHk9flRvdGFsT3V0Ym91bmQsIHR5cGU9InNjYXR0ZXIiLCBuYW1lPSdPdXRib3VuZCcsIG1vZGU9J2xpbmVzJywgbGluZSA9IGxpc3QoY29sb3I9ImJsdWUiLCB3aWR0aCA9IDEpLCBzaG93bGVnZW5kPUYpCgpwNCA8LSByZWdpb25hbF90cmF2ZWwgJT4lIAogICBmaWx0ZXIoUmVnaW9uPT0nZXVyb3BlJykgJT4lIAogICBwbG90X2x5KHggPSB+YXMuUE9TSVhjdChEYXRlKSkgJT4lCiAgIGFkZF90cmFjZSh5PX5Ub3RhbEluYm91bmQsIHR5cGU9InNjYXR0ZXIiLCBuYW1lPSdJbmJvdW5kJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0iZ3JheSIsIHdpZHRoID0gMSksIHNob3dsZWdlbmQ9RikgJT4lCiAgIGFkZF90cmFjZSh5PX5Ub3RhbE91dGJvdW5kLCB0eXBlPSJzY2F0dGVyIiwgbmFtZT0nT3V0Ym91bmQnLCBtb2RlPSdsaW5lcycsIGxpbmUgPSBsaXN0KGNvbG9yPSJibHVlIiwgd2lkdGggPSAxKSwgc2hvd2xlZ2VuZD1GKQoKcDUgPC0gcmVnaW9uYWxfdHJhdmVsICU+JSAKICAgZmlsdGVyKFJlZ2lvbj09J2xhdGluIGFtZXJpY2EgZXhjbCBtZXhpY28nKSAlPiUgCiAgIHBsb3RfbHkoeCA9IH5hcy5QT1NJWGN0KERhdGUpKSAlPiUKICAgYWRkX3RyYWNlKHk9flRvdGFsSW5ib3VuZCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J0luYm91bmQnLCBtb2RlPSdsaW5lcycsIGxpbmUgPSBsaXN0KGNvbG9yPSJncmF5Iiwgd2lkdGggPSAxKSwgc2hvd2xlZ2VuZD1GKSAlPiUKICAgYWRkX3RyYWNlKHk9flRvdGFsT3V0Ym91bmQsIHR5cGU9InNjYXR0ZXIiLCBuYW1lPSdPdXRib3VuZCcsIG1vZGU9J2xpbmVzJywgbGluZSA9IGxpc3QoY29sb3I9ImJsdWUiLCB3aWR0aCA9IDEpLCBzaG93bGVnZW5kPUYpCnA2IDwtIHJlZ2lvbmFsX3RyYXZlbCAlPiUgCiAgIGZpbHRlcihSZWdpb249PSdtZXhpY28nKSAlPiUgCiAgIHBsb3RfbHkoeCA9IH5hcy5QT1NJWGN0KERhdGUpKSAlPiUKICAgYWRkX3RyYWNlKHk9flRvdGFsSW5ib3VuZCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J0luYm91bmQnLCBtb2RlPSdsaW5lcycsIGxpbmUgPSBsaXN0KGNvbG9yPSJncmF5Iiwgd2lkdGggPSAxKSwgc2hvd2xlZ2VuZD1GKSAlPiUKICAgYWRkX3RyYWNlKHk9flRvdGFsT3V0Ym91bmQsIHR5cGU9InNjYXR0ZXIiLCBuYW1lPSdPdXRib3VuZCcsIG1vZGU9J2xpbmVzJywgbGluZSA9IGxpc3QoY29sb3I9ImJsdWUiLCB3aWR0aCA9IDEpLCBzaG93bGVnZW5kPUYpCgpwNyA8LSByZWdpb25hbF90cmF2ZWwgJT4lIAogICBmaWx0ZXIoUmVnaW9uPT0nbWlkZGxlIGVhc3QnKSAlPiUgCiAgIHBsb3RfbHkoeCA9IH5hcy5QT1NJWGN0KERhdGUpKSAlPiUKICAgYWRkX3RyYWNlKHk9flRvdGFsSW5ib3VuZCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J0luYm91bmQnLCBtb2RlPSdsaW5lcycsIGxpbmUgPSBsaXN0KGNvbG9yPSJncmF5Iiwgd2lkdGggPSAxKSwgc2hvd2xlZ2VuZD1GKSAlPiUKICAgYWRkX3RyYWNlKHk9flRvdGFsT3V0Ym91bmQsIHR5cGU9InNjYXR0ZXIiLCBuYW1lPSdPdXRib3VuZCcsIG1vZGU9J2xpbmVzJywgbGluZSA9IGxpc3QoY29sb3I9ImJsdWUiLCB3aWR0aCA9IDEpLCBzaG93bGVnZW5kPUYpCgpwOCA8LSByZWdpb25hbF90cmF2ZWwgJT4lIAogICBmaWx0ZXIoUmVnaW9uPT0nb2NlYW5pYScpICU+JSAKICAgcGxvdF9seSh4ID0gfmFzLlBPU0lYY3QoRGF0ZSkpICU+JQogICBhZGRfdHJhY2UoeT1+VG90YWxJbmJvdW5kLCB0eXBlPSJzY2F0dGVyIiwgbmFtZT0nSW5ib3VuZCcsIG1vZGU9J2xpbmVzJywgbGluZSA9IGxpc3QoY29sb3I9ImdyYXkiLCB3aWR0aCA9IDEpLCBzaG93bGVnZW5kPUYpICU+JQogICBhZGRfdHJhY2UoeT1+VG90YWxPdXRib3VuZCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J091dGJvdW5kJywgbW9kZT0nbGluZXMnLCBsaW5lID0gbGlzdChjb2xvcj0iYmx1ZSIsIHdpZHRoID0gMSksIHNob3dsZWdlbmQ9RikKCnN1YnBsb3QocDEsIHAyLCBwMywgcDQsIHA1LCBwNiwgcDcsIHA4LCBucm93cz04KSAlPiUKICBsYXlvdXQodGl0bGUgPSAiUmVnaW9uYWwgSW5ib3VuZCBhbmQgT3V0Ym91bmQiLAogICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiQWZyaWNhIiksCiAgICAgICAgIHlheGlzMiA9IGxpc3QodGl0bGUgPSAiQXNpYSIpLCAKICAgICAgICAgeWF4aXMzID0gbGlzdCh0aXRsZSA9ICJDYW5hZGEiKSwKICAgICAgICAgeWF4aXM0ID0gbGlzdCh0aXRsZSA9ICJFdXJvcGUiKSwKICAgICAgICAgeWF4aXM1ID0gbGlzdCh0aXRsZSA9ICJMYXRpbiBBbWVyaWNhIiksCiAgICAgICAgIHlheGlzNiA9IGxpc3QodGl0bGUgPSAiTWV4aWNvIiksCiAgICAgICAgIHlheGlzNyA9IGxpc3QodGl0bGUgPSAiTWlkZGxlIEVhc3QiKSwKICAgICAgICAgeWF4aXM4ID0gbGlzdCh0aXRsZSA9ICJPY2VhbmlhIiksCiAgICAgICAgIGxlZ2VuZCA9IGxpc3Qob3JpZW50YXRpb24gPSAnaCcsIHggPSAwLCB5ID0gMS4wMDUpCiAgICAgICAgICkKYGBgCgoKLSBBZnJpY2E6IFRoZXJlIGFyZSBtb3JlIGFuZCBtb3JlIHBlb3BsZSBmcm9tIEFmcmljYSB0cmF2ZWwgdG8gVS5TLiBzaW5jZSAyMDEzLCBidXQgdGhlIG51bWJlciBvZiBhbWVyaWNhbiB3aG8gZ28gdG8gQWZyaWNhIGlzIHZlcnkgc3RhYmxlIGZvciBwYXN0IDcgeWVhcnMuCiAgICAgIAotIEFzaWE6IE1vcmUgYW5kIG1vcmUgQXNpYXMgY29tZSB0byBVLlMsIGhvd2V2ZXIsIGxlc3MgQW1lcmljYW5zIGdvIHRvIEFzaWEgYWZ0ZXIgTWF5IDIwMTAuIEFub3RoZXIgdGhpbmcgdG8gbm90aWNlIGlzIHRoZSBudW1iZXIgb2YgdmlzaXRvcnMgZnJvbSBBc2lhIGdyb3dzIGZhc3RlciBpbiBKdWx5IGNvbXBhcmUgdG8gb3RoZXIgbW9udGguIFRoaXMgaXMgcHJvYmFiYWx5IGR1ZSB0byB0aGUgaW5jcmVhc2Ugb2YgZm9yZWlnbiBzdHVkZW50cy4KCi0gQ2FuYWRhOiAKCi0gRXVyb3BlOiAKCi0gTGF0aW4gQW1lcmljYSBleGNlcHQgTWV4aWNvOiAKCi0gTWV4aWNvOiBBIGJvb20gb2YgbnVtYmVyIG9mIG91dGJvdW5kIGhhcHBlbnMgaW4gdGhlIGVuZCBvZiAyMDA5LiBXZSBkaWQgYSBsb3QgcmVzZWFyY2ggb25saW5lIGFuZCBmb3VuZCBuZXdzIGFib3V0IHdpdGggdG9waWNzIGFib3V0IE1vcmUgTWV4aWNhbnMgTGVhdmluZyBUaGFuIENvbWluZyB0byB0aGUgVS5TLiBTbyB3ZSB0aGluayB0aGUgCgotIE1pZGRsZSBFYXN0OiBCb3RoIHRoZSBudW1iZXIgb2YgaW5ib3VuZCBhbmQgb3V0Ym91bmQgaW5jcmVhc2UgYnkgeWVhci4KCgotIE9jZWFuaWE6IExpa2UgQXNpYSwgbGVzcyBvZiBVLlMuIGNpdGl6ZW5zIHZpc2l0IE9jZWFuaWEgcmVnaW9uIHNpbmNlIG1pZCAyMDEwLiAKCgpUaGVuIHdlIG1vdmUgdG8gdGhlIE91dGJvdW5kIG9mIGFsbCByZWdpb25zLCBmcm9tIGdyYXBoIGJlbG93ZSB3ZSBvYnNlcnZlIHNldmVyYWwgdGhpbmdzOgoxLiBNZXhpY28gaXMgdGhlIG51bWJlciBvbmUgT3V0Ym91bmQgY291bnRyeS4gCjIuIEEgaHVnZSBwdW1wIGhhcHBlbmQgb24gMjAwOSBmb3IgTWV4aWNvLgozLiBPdXRib3VuZCBudW1iZXIgb2YgbWV4aWNvIGlzIGluY3JlYXNpbmcsIGhvd2V2ZXIgZm9yIG90aGVyIHJlZ2lvbnMgaXQgc2VlbXMgc3RhYmxlLgo0LiBMaWtlIEluYm91bmQsIE91dGJvdW5kIHNob3dzIGEgc2Vhc29uYWwgcGF0dGVybiBhcyB3ZWxsLgoKClNpbmNlIENhbmFkYSBhbmQgTWV4aWNvIGRvbWluYXRlIHRoZSBudW1iZXIgb2YgcGVvcGxlIGFuZCB0aGUgaW50ZXJlc3Qgb2YgZGlmZmVyZW50IGJlaGF2aW91ciBwZXIgcmVnaW9uLCB3ZSBzdGFydCBsb29raW5nIGF0IGluYm91bmQgYW5kIG91dGJvdW5kIHBlciByZWdpb24uIAoKCiMjIyMgU3BlbmQgQW5hbHlzaXMKCmBgYHtyfQp5ZWFybHlfc3BlbmQgPC0gdGlkeV9udHRvX3NwZW5kX3kgJT4lIAogICBmaWx0ZXIoUmVnaW9uIT0nZXVyb3BlYW4gdW5pb24nLCBSZWdpb24hPSdzb3V0aC1jZW50cmFsIGFtZXJpY2EnLCBSZWdpb24hPSdvdmVyc2VhcycpICU+JSAKICAgbXV0YXRlKFJlZ2lvbj1yZWNvZGUoUmVnaW9uLCAiYXNpYS1wYWNpZmljIj0iYXNpYSIpLCBTcGVuZD1TcGVuZCoxMDAwMDAwKSAlPiUgCiAgIHNlbGVjdCgtTWlzc2luZykgJT4lIAogICBhcnJhbmdlKFJlZ2lvbiwgWWVhciwgVHlwZSwgQ2F0ZWdvcnkpIApgYGAKCmBgYHtyfQp5ZWFybHlfc3BlbmQgJT4lCiAgIGdyb3VwX2J5KFR5cGUsIFllYXIpICU+JQogICBzdW1tYXJpc2UoVG90YWxTcGVuZD1zdW0oU3BlbmQpKSAlPiUgCiAgIHNwcmVhZChUeXBlLCBUb3RhbFNwZW5kKSAlPiUKICAgdW5ncm91cCAlPiUgCiAgIHBsb3RfbHkoeCA9IH5ZZWFyKSAlPiUKICAgYWRkX3RyYWNlKHk9fmBQYXltZW50cyAoaW1wb3J0cylgLCB0eXBlPSJzY2F0dGVyIiwgbmFtZT0nUGF5bWVudHMgKGltcG9ydHMpJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbGluZSA9IGxpc3QoY29sb3I9ImJsdWUiLCB3aWR0aCA9IDEpKSAlPiUKICAgYWRkX3RyYWNlKHk9fmBSZWNlaXB0cyAoZXhwb3J0cylgLCB0eXBlPSJzY2F0dGVyIiwgbmFtZT0nUmVjZWlwdHMgKGV4cG9ydHMpJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbGluZSA9IGxpc3Qod2lkdGggPSAxKSkgJT4lIAogICBsYXlvdXQodGl0bGUgPSAiWWVhcmx5IFNwZW5kaW5nIiwgCiAgICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiWWVhciIpLCB5YXhpcyA9IGxpc3QodGl0bGUgPSAiU3BlbmQiKSwgCiAgICAgICAgICBsZWdlbmQgPSBsaXN0KG9yaWVudGF0aW9uID0gJ2gnLCB4ID0gMC41LCB5ID0gMS4wMDUpKQoKYGBgCgoKYGBge3J9CnllYXJseV9zcGVuZCAlPiUKICAgZ3JvdXBfYnkoVHlwZSwgWWVhcikgJT4lCiAgIHN1bW1hcmlzZShUb3RhbFNwZW5kPXN1bShTcGVuZCkpICU+JSAKICAgc3ByZWFkKFR5cGUsIFRvdGFsU3BlbmQpICU+JQogICBwbG90X2x5KHggPSB+WWVhciwgeSA9IH5gUGF5bWVudHMgKGltcG9ydHMpYCwgdHlwZSA9ICdiYXInLCBuYW1lID0gJ1BheW1lbnRzJywgbWFya2VyID0gbGlzdChjb2xvciA9ICdyZ2IoNTUsIDgzLCAxMDkpJykpICU+JQogICBhZGRfdHJhY2UoeSA9IH5gUmVjZWlwdHMgKGV4cG9ydHMpYCwgbmFtZSA9ICdSZWNlaXB0cycsIG1hcmtlciA9IGxpc3QoY29sb3IgPSAncmdiKDI2LCAxMTgsIDI1NSknKSkgJT4lCiAgIGxheW91dCh0aXRsZSA9ICdZZWFybHkgU3BlbmRpbmcnLAogICAgICAgICB4YXhpcyA9IGxpc3QoCiAgICAgICAgICAgdGl0bGUgPSAiIiwKICAgICAgICAgICB0aWNrZm9udCA9IGxpc3QoCiAgICAgICAgICAgICBzaXplID0gMTQsCiAgICAgICAgICAgICBjb2xvciA9ICdyZ2IoMTA3LCAxMDcsIDEwNyknKSksCiAgICAgICAgIHlheGlzID0gbGlzdCgKICAgICAgICAgICB0aXRsZSA9ICdTcGVuZCAoQmlsbGlvbiAkKScsCiAgICAgICAgICAgdGl0bGVmb250ID0gbGlzdCgKICAgICAgICAgICAgIHNpemUgPSAxNiwKICAgICAgICAgICAgIGNvbG9yID0gJ3JnYigxMDcsIDEwNywgMTA3KScpLAogICAgICAgICAgIHRpY2tmb250ID0gbGlzdCgKICAgICAgICAgICAgIHNpemUgPSAxNCwKICAgICAgICAgICAgIGNvbG9yID0gJ3JnYigxMDcsIDEwNywgMTA3KScpKSwKICAgICAgICAgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICdoJywgeCA9IDAsIHkgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICBiZ2NvbG9yID0gJ3JnYmEoMjU1LCAyNTUsIDI1NSwgMCknLCBib3JkZXJjb2xvciA9ICdyZ2JhKDI1NSwgMjU1LCAyNTUsIDApJyksCiAgICAgICAgIGJhcm1vZGUgPSAnZ3JvdXAnLCBiYXJnYXAgPSAwLjE1LCBiYXJncm91cGdhcCA9IDAuMSkKYGBgCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KeWVhcmx5X3NwZW5kICU+JSAKICAgZmlsdGVyKFR5cGU9PSJQYXltZW50cyAoaW1wb3J0cykiKSAlPiUgCiAgIHNlbGVjdCgtVHlwZSkgJT4lIAogICBncm91cF9ieShSZWdpb24sIFllYXIpICU+JSAKICAgc3VtbWFyaXNlKFRvdGFsU3BlbmQ9c3VtKFNwZW5kKSkgJT4lIAogICBzcHJlYWQoUmVnaW9uLCBUb3RhbFNwZW5kKSAlPiUgCiAgIHBsb3RfbHkoeCA9IH5ZZWFyKSAlPiUKICAgYWRkX3RyYWNlKHk9fmFmcmljYSwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J2FmcmljYScsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIGxpbmUgPSBsaXN0KHdpZHRoID0gMikpICU+JQogICBhZGRfdHJhY2UoeT1+YXNpYSwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J2FzaWEnLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBsaW5lID0gbGlzdCh3aWR0aCA9IDIpKSAlPiUKICAgYWRkX3RyYWNlKHk9fmV1cm9wZSwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J2V1cm9wZScsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIGxpbmUgPSBsaXN0KHdpZHRoID0gMikpICU+JQogICBhZGRfdHJhY2UoeT1+YGxhdGluIGFtZXJpY2FgLCB0eXBlPSJzY2F0dGVyIiwgbmFtZT0nbGF0aW4gYW1lcmljYScsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIGxpbmUgPSBsaXN0KHdpZHRoID0gMikpICU+JQogICBhZGRfdHJhY2UoeT1+YG1pZGRsZSBlYXN0YCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J21pZGRsZSBlYXN0JywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbGluZSA9IGxpc3Qod2lkdGggPSAyKSkgJT4lIAogICBsYXlvdXQodGl0bGUgPSAiUGF5bWVudHMgKGltcG9ydHMpIiwgCiAgICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiWWVhciIpLCAKICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJTcGVuZCIpLAogICAgICAgICAgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICdoJykpCmBgYAoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnllYXJseV9zcGVuZCAlPiUgCiAgIGZpbHRlcihUeXBlPT0iUmVjZWlwdHMgKGV4cG9ydHMpIikgJT4lIAogICBzZWxlY3QoLVR5cGUpICU+JSAKICAgZ3JvdXBfYnkoUmVnaW9uLCBZZWFyKSAlPiUgCiAgIHN1bW1hcmlzZShUb3RhbFNwZW5kPXN1bShTcGVuZCkpICU+JSAKICAgc3ByZWFkKFJlZ2lvbiwgVG90YWxTcGVuZCkgJT4lIAogICBwbG90X2x5KHggPSB+WWVhcikgJT4lCiAgIGFkZF90cmFjZSh5PX5hZnJpY2EsIHR5cGU9InNjYXR0ZXIiLCBuYW1lPSdhZnJpY2EnLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBsaW5lID0gbGlzdCh3aWR0aCA9IDEpKSAlPiUKICAgYWRkX3RyYWNlKHk9fmFzaWEsIHR5cGU9InNjYXR0ZXIiLCBuYW1lPSdhc2lhJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbGluZSA9IGxpc3Qod2lkdGggPSAxKSkgJT4lCiAgIGFkZF90cmFjZSh5PX5ldXJvcGUsIHR5cGU9InNjYXR0ZXIiLCBuYW1lPSdldXJvcGUnLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBsaW5lID0gbGlzdCh3aWR0aCA9IDEpKSAlPiUKICAgYWRkX3RyYWNlKHk9fmBsYXRpbiBhbWVyaWNhYCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J2xhdGluIGFtZXJpY2EnLCBtb2RlID0gJ2xpbmVzK21hcmtlcnMnLCBsaW5lID0gbGlzdCh3aWR0aCA9IDEpKSAlPiUKICAgYWRkX3RyYWNlKHk9fmBtaWRkbGUgZWFzdGAsIHR5cGU9InNjYXR0ZXIiLCBuYW1lPSdtaWRkbGUgZWFzdCcsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIGxpbmUgPSBsaXN0KHdpZHRoID0gMSkpICU+JSAKICAgbGF5b3V0KHRpdGxlID0gIlJlY2VpcHRzIChleHBvcnRzKSIsIAogICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlllYXIiKSwgCiAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiU3BlbmQiKSwgCiAgICAgICAgICBsZWdlbmQgPSBsaXN0KG9yaWVudGF0aW9uID0gJ2gnKSkKYGBgCgoKYGBge3J9CnllYXJseV9zcGVuZCAlPiUKICAgZ3JvdXBfYnkoVHlwZSwgWWVhcikgJT4lCiAgIHN1bW1hcmlzZShUb3RhbFNwZW5kPXN1bShTcGVuZCkpICU+JSAKICAgc3ByZWFkKFR5cGUsIFRvdGFsU3BlbmQpICU+JQogICBwbG90X2x5KHggPSB+WWVhcikgJT4lCiAgIGFkZF90cmFjZSh5PX5gUGF5bWVudHMgKGltcG9ydHMpYCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J1BheW1lbnRzIChpbXBvcnRzKScsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIGxpbmUgPSBsaXN0KGNvbG9yPSJibHVlIiwgd2lkdGggPSAxKSkgJT4lCiAgIGFkZF90cmFjZSh5PX5gUmVjZWlwdHMgKGV4cG9ydHMpYCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J1JlY2VpcHRzIChleHBvcnRzKScsIG1vZGUgPSAnbGluZXMrbWFya2VycycsIGxpbmUgPSBsaXN0KHdpZHRoID0gMSkpICU+JSAKICAgbGF5b3V0KHRpdGxlID0gIkFmcmljYSIsIAogICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlllYXIiKSwgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlNwZW5kIiksIAogICAgICAgICAgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICdoJywgeCA9IDAuNSwgeSA9IDEuMDA1KSkKYGBgCgoKCmBgYHtyfQp0aWR5X3diX2dkcCAlPiUgCiAgIGZpbHRlcihDb3VudHJ5Q29kZT09IlVTQSIsIFllYXI+MjAwMCwgWWVhcjwyMDE2KSAlPiUgCiAgIHNlbGVjdChZZWFyLCBHRFApICU+JSAKICAgbXV0YXRlKFllYXI9ZmFjdG9yKFllYXIpKSAlPiUgCiAgIHBsb3RfbHkoeCA9IH5ZZWFyKSAlPiUKICAgYWRkX3RyYWNlKHk9fkdEUCwgdHlwZT0ic2NhdHRlciIsIG5hbWU9J1VTJywgbW9kZSA9ICdsaW5lcyttYXJrZXJzJywgbGluZSA9IGxpc3Qod2lkdGggPSAxKSkKYGBgCgoKYGBge3J9CnllYXJseV9zcGVuZCAlPiUgCiAgIGZpbHRlcihUeXBlPT0iUmVjZWlwdHMgKGV4cG9ydHMpIikgJT4lIAogICBzZWxlY3QoLVR5cGUsIC1SZWdpb24pICU+JSAKICAgZ3JvdXBfYnkoQ2F0ZWdvcnksIFllYXIpICU+JSAKICAgc3VtbWFyaXNlKFRvdGFsU3BlbmQ9c3VtKFNwZW5kKSkgJT4lIAogICBzcHJlYWQoQ2F0ZWdvcnksIFRvdGFsU3BlbmQpICU+JSAKICAgcGxvdF9seSh4ID0gflllYXIsIHkgPSB+RWR1Y2F0aW9uLCB0eXBlID0gJ2JhcicsIG5hbWUgPSAnRWR1Y2F0aW9uJykgJT4lCiAgIGFkZF90cmFjZSh5ID0gfmBNZWRpY2FsL1Nob3J0LVRlcm0gV29ya2Vyc2AsIG5hbWUgPSAnTWVkaWNhbC9TaG9ydC1UZXJtIFdvcmtlcnMnKSAlPiUgCiAgIGFkZF90cmFjZSh5ID0gfmBPdGhlciBCdXNpbmVzcy9PdGhlciBQZXJzb25hbCBUcmF2ZWxgLCBuYW1lID0gJ090aGVyIEJ1c2luZXNzL090aGVyIFBlcnNvbmFsIFRyYXZlbCcpICU+JSAKICAgbGF5b3V0KHlheGlzID0gbGlzdCh0aXRsZSA9ICdTcGVuZCcpLCBiYXJtb2RlID0gJ2dyb3VwJykKYGBgCgpgYGB7cn0KeWVhcmx5X3NwZW5kICU+JSAKICAgZmlsdGVyKFR5cGU9PSJSZWNlaXB0cyAoZXhwb3J0cykiKSAlPiUgCiAgIHNlbGVjdCgtVHlwZSwgLVJlZ2lvbikgJT4lIAogICBncm91cF9ieShDYXRlZ29yeSwgWWVhcikgJT4lIAogICBzdW1tYXJpc2UoVG90YWxTcGVuZD1zdW0oU3BlbmQpKSAlPiUgCiAgIHNwcmVhZChDYXRlZ29yeSwgVG90YWxTcGVuZCkgJT4lIAogICBwbG90X2x5KHggPSB+WWVhciwgeSA9IH5FZHVjYXRpb24sIHR5cGUgPSAnYmFyJywgbmFtZSA9ICdFZHVjYXRpb24nKSAlPiUKICAgYWRkX3RyYWNlKHkgPSB+YE1lZGljYWwvU2hvcnQtVGVybSBXb3JrZXJzYCwgbmFtZSA9ICdNZWRpY2FsL1Nob3J0LVRlcm0gV29ya2VycycpICU+JSAKICAgYWRkX3RyYWNlKHkgPSB+YE90aGVyIEJ1c2luZXNzL090aGVyIFBlcnNvbmFsIFRyYXZlbGAsIG5hbWUgPSAnT3RoZXIgQnVzaW5lc3MvT3RoZXIgUGVyc29uYWwgVHJhdmVsJykgJT4lIAogICBsYXlvdXQoeWF4aXMgPSBsaXN0KHRpdGxlID0gJ1NwZW5kJyksIGJhcm1vZGUgPSAnZ3JvdXAnKQpgYGAKCgpGaW5hbGx5LCB3ZSBzZWxlY3Qgc2V2ZXJhbCByZWdpb24gYW5kIGNvbWJpbmUgaW5ib3VuZCwgb3V0Ym91bmQgd2l0aCBHRFAKCgojIyBDb25jbHVzaW9uCj4gRGlzY3VzcyBsaW1pdGF0aW9ucyBhbmQgZnV0dXJlIGRpcmVjdGlvbnMsIGxlc3NvbnMgbGVhcm5lZC4KCkEgbm90ZSBvbiBzdHlsZToKWW91IGFyZSBlbmNvdXJhZ2VkIHRvIGJlIGFzIGludGVsbGVjdHVhbGx5IGhvbmVzdCBhcyBwb3NzaWJsZS4gVGhhdCBtZWFucyBwb2ludGluZyBvdXQgZmxhd3MgaW4geW91ciB3b3JrLCBkZXRhaWxpbmcgb2JzdGFjbGVzLCBkaXNhZ3JlZW1lbnRzLCBkZWNpc2lvbiBwb2ludHMsIGV0Yy4gLS0gdGhlIGtpbmRzIG9mICJiZWhpbmQtdGhlLXNjZW5lIiB0aGluZ3MgdGhhdCBhcmUgaW1wb3J0YW50IGJ1dCBvZnRlbiBsZWZ0IG91dCBvZiByZXBvcnRzLiBZb3UgbWF5IHVzZSB0aGUgZmlyc3QgcGVyc29uICgiSSIvIldlIikgb3Igc3BlY2lmaWMgdGVhbSBtZW1iZXJzJyBuYW1lcywgYXMgcmVsZXZhbnQuCgoKVGhlIGdvYWwgb2YgdGhpcyBwcm9qZWN0IGlzIHRvIGFuc3dlciB0aGUgZm91ciBxdWVzdGlvbnMgcmFpc2VkIGFib3ZlLiBXZSBoYXZlIGFjY29tcGxpc2hlZCB0aGUgdGFzayBkZXNwaXRlIG9mIHNvbWUgZmxhd3MgYW5kIGxpbWl0YXRpb25zLiBGb3IgaW5zdGFuY2UsIHRoZSBsYXRlc3QgZGF0YSB3ZSBjb3VsZCBmaW5kIGlzIGZvciB0aGUgeWVhciAyMDE1LCB3aGljaCBpcyBtb3JlIHRoYW4gb25lIHllYXIgYWdvLiBJbiB0aGF0IGNhc2UsIHdlIGNvdWxkIG5vdCBzYXkgdGhlIGFuYWx5c2lzIGlzIHZlcnkgcGVyc3Vhc2l2ZSBzaW5jZSB0aGUgZGF0YSBzb3VyY2UgaXMgbm90IHVwIHRvIGRhdGUuIFdlIGFyZSB1bmFibGUgdG8gZ2V0IGRhdGEgdGhhdCBhcmUgbW9yZSBkZXRhaWxlZCBzbyB0aGF0IHdlIGNhbm5vdCBkaWcgZGVlcGVyIHRvIGZpbmQgcm9vdCBjYXVzZXMgb2Ygc29tZSBvYnNlcnZhdGlvbnMuIEF0IHRoZSB2ZXJ5IGJlZ2lubmluZywgd2UgdGhvdWdodCB0aGUgZGF0YSB3YXMgZXhoYXVzdGl2ZSBhbmQgY29tcHJlaGVuc2l2ZSBhbmQgd2UgbWFkZSBwbGVudHkgb2YgaHlwb3RoZXNlcyBhbmQgZXhwZWN0YXRpb25zIGJhc2VkIG9uIHRoZSBmaXJzdCBpbXByZXNzaW9uOyBob3dldmVyLCB3ZSBmaW5kIHRoYXQgbW9zdCBvZiBvdXIgaWRlYXMgYXJlIG5vdCByZWFsaXN0aWMgYXMgd2UgaW52ZXN0aWdhdGUgdGhlIGRhdGEgbW9yZS4gVW5mb3J0dW5hdGVseSwgd2UgaGF2ZSB0byBkaXNjYXJkIHNvbWUgaW50ZXJlc3RpbmcgaWRlYXMgZHVlIHRoZSBpbmNvbnN0YW5jeSBpbiB0aGUgZGF0YXNldC4gCkZvciB0aGUgZnV0dXJlIHdvcmssIHdlIGNvdWxkIGludHJvZHVjZSBtb3JlIHN1cHBvcnRpdmUgZGF0YSBzdWNoIGFzIHRoZSBpbmJvdW5kIGFuZCBvdXRib3VuZCB0cmF2ZWxlciBkYXRhIG9mIG90aGVyIGNvdW50cmllcywgYW5kIHRoZW4gY29tcGFyZSBpdCB3aXRoIHRoZSBVU0EuIFdlIGJlbGlldmUgdGhhdCBpdCB3b3VsZCByZXZlYWwgcmVzdWx0cyB0aGF0IGFyZSBtb3JlIGludGVyZXN0aW5nLgoKCgo=